那么,在传统的ADO.NET中,人们可以简单地更改DB并且几乎独立于DB?
当然你可以,但为了能够做到这一点,我们必须揭穿这种说法。
似乎是魔法药丸,但所有的ADO.NET语句都是硬编码的。
这不是ADO.NET的副产品 - 这是您的架构的副产品。你在错误的地方构建SQL语句。您需要具体的,供应商特定的模型,这些模型能够在供应商之间构建不同的声明。这并不像听起来那么糟糕 - 大多数语句都可以利用反射自动生成 - 这只是特殊情况。
例如,假设我有一个像这样的模式:
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
}
,让我们说,我想生成SELECT
声明了这一点。好了,我要首先需要一对夫妇的属性来告诉我什么属性是PK,什么性质的数据字段:
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
internal sealed class DataFieldAttribute : Attribute
{
public DataFieldAttribute()
{
}
}
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
sealed class PrimaryKeyAttribute : Attribute
{
public PrimaryKeyAttribute()
{
}
}
,现在我需要装饰该类:
public class Employee
{
[PrimaryKey]
public int ID { get; set; }
[DataField]
public string Name { get; set; }
[DataField]
public DateTime DateOfBirth { get; set; }
}
现在我只需要一个简单的过程,以创建一个SELECT
声明,所以首先让我们构建一个基础数据模型类:
public abstract class DataModelBase
{
protected string _primaryKeyField;
protected List<string> _props = new List<string>();
public DataModelBase()
{
PropertyInfo pkProp = this.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(PrimaryKeyAttribute), false).Length > 0).FirstOrDefault();
if (pkProp != null)
{
_primaryKeyField = pkProp.Name;
}
foreach (PropertyInfo prop in this.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(DataFieldAttribute), false).Length > 0))
{
_props.Add(prop.Name);
}
}
public virtual string TableName { get { return this.GetType().Name; } }
public virtual string InsertStatement
{
get
{
return string.Format("INSERT INTO [{0}] ({1}) VALUES ({2})",
this.TableName,
GetDelimitedSafeFieldList(", "),
GetDelimitedSafeParamList(", "));
}
}
public virtual string UpdateStatement
{
get
{
return string.Format("UPDATE [{0}] SET {1} WHERE [{2}] = @{2}",
this.TableName,
GetDelimitedSafeSetList(", "),
_primaryKeyField);
}
}
public virtual string DeleteStatement
{
get
{
return string.Format("DELETE [{0}] WHERE [{1}] = @{1}",
this.TableName,
_primaryKeyField);
}
}
public virtual string SelectStatement
{
get
{
return string.Format("SELECT [{0}], {1} FROM [{2}]",
_primaryKeyField,
GetDelimitedSafeFieldList(", "),
this.TableName);
}
}
protected string GetDelimitedSafeParamList(string delimiter)
{
return string.Join(delimiter, _props.Select(k => string.Format("@{0}", k)));
}
protected string GetDelimitedSafeFieldList(string delimiter)
{
return string.Join(delimiter, _props.Select(k => string.Format("[{0}]", k)));
}
protected string GetDelimitedSafeSetList(string delimiter)
{
return string.Join(delimiter, _props.Select(k => string.Format("[{0}] = @{0}", k)));
}
}
,现在让我们从数据模型继承:
public class Employee : DataModelBase
和繁荣,现在我可以随时获得这些声明,我需要它们,这些声明现在适用于任何具体的提供商。
然后我就用Dapper to get the data,因为它利用了IDbConnection
界面像你需要什么和这是可笑的快速 - 和你去那里 - 供应商的独立解决方案,能够很容易地扩展,如果建立的Employee
的Oracle版本必要。
这个框架有转化为已选定DB statesment,这看起来忠实地仙丹
当然,它可能看起来像一个神奇的药丸内部独立于语言的语句,但它确实在骂很多方法。您没有灵活性(至少这不是容易的)来构建针对您的需求进行优化以支持高事务和数据库的语句。你真的受制于这里的主人。 .NET Entity Framework会为您构建这些语句,我甚至无法计算StackOverflow上有多少问题已经完成,我如何更改由此LINQ语句利用.NET Entity Framework生成的SQL。
如何,我们可以添加使用POCO类的在此处创建表的方法或生成创建表脚本? – ashy