程序员需要的是一种以标准、一致和强大的方式概括不同数据系统的方法。在 .NET 应用程序开发领域,Microsoft ADO.NET 满足了这一需求。使用 ADO.NET 的程序员不必担心与不同数据库系统相关的细节,而是专注于数据内容本身。
来自“ADO.NET 4 Step by Step”一书
一直在思考下一个结构。
ADO.NET 可以分为两部分:
1. 经典 ADO.NET(数据集、数据表等)。在经典变体中,有不同的 DB 连接提供程序,每个提供程序将 DB 内部数据转换为 .NET。例如,MS SQL Server 以一种方式保存数据,而 Oracle 以另一种方式保存数据。所以我们可以通过改变提供者来改变数据库。
看似灵丹妙药,但所有 ADO.NET 语句都是硬编码的。
对于 MS SQL 前 10 条选择语句是SELECT TOP 10 ROWS FROM TABLE,对于 Oracle SELECT ROWS FROM TABELE WHERE ROWNUM <= 10。似乎更改数据库和提供程序无济于事,不是吗?
2. 实体框架。该框架具有内部独立的语言语句,可以转换为选择的 DB 语句,这看起来真的很神奇:
LINQ -> 内部 EF 语句 -> MS SQL DB,
LINQ -> 内部 EF 语句 -> Oracle DB。
那么在经典的 ADO.NET 中,可以简单地更改 DB 并几乎独立于 DB 吗?
那么在经典的 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; }
}
Run Code Online (Sandbox Code Playgroud)
假设我想从中生成一个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()
{
}
}
Run Code Online (Sandbox Code Playgroud)
现在我需要装饰那个类:
public class Employee
{
[PrimaryKey]
public int ID { get; set; }
[DataField]
public string Name { get; set; }
[DataField]
public DateTime DateOfBirth { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
现在我只需要一个简单的过程来创建一个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)));
}
}
Run Code Online (Sandbox Code Playgroud)
现在让我们继承该数据模型:
public class Employee : DataModelBase
Run Code Online (Sandbox Code Playgroud)
和繁荣,现在我可以在任何需要的时候得到这些声明,这些声明现在适用于任何具体的提供者。
然后我将使用Dapper 来获取数据,因为它利用了IDbConnection您所需要的界面,而且速度快得离谱 - 就这样 - 一个独立于提供者的解决方案,Employee如果需要,可以轻松扩展以构建 Oracle 版本。
这个框架有内部独立的语言语句,可以转换为选择的 DB 语句,看起来真的很神奇
当然,它可能看起来像一颗灵丹妙药,但在很多方面它确实是一种诅咒。您没有灵活性(至少不容易)构建针对您的需求进行优化以支持高事务和容量数据库的语句。在这里,你真的受制于师父。.NET Entity Framework 为您构建了这些语句,我什至无法计算在 StackOverflow 上有多少关于如何利用 .NET Entity Framework 更改此 LINQ 语句生成的 SQL 的问题。
| 归档时间: |
|
| 查看次数: |
4593 次 |
| 最近记录: |