2013-04-01 51 views
1

程序员需要的是一种以标准,一致和强大的方式推广不同数据系统 的方法。在.NET 应用程序开发的世界中,Microsoft ADO.NET满足了这种需求。代替 担心与不同数据库 系统相关的细节,使用ADO.NET的程序员专注于数据内容本身。ADO.NET独特的数据库

从书 “ADO.NET 4分步实施”

总是想着下一个结构。

ADO.NET可以在两个部分无法相依:

1.经典ADO.NET(数据集,数据表等)。在经典变体中,有不同的数据库连接提供程序,每个提供程序都将数据库内部数据转换为.NET。例如,MS SQL Server以一种方式保存数据,另一种方式保存Oracle。所以我们可以通过改变提供者来改变数据库。

似乎是魔力丸,但是所有的ADO.NET语句都是硬编码的。

对于MS SQL top 10选择语句是SELECT TOP 10 ROWS FROM TABLE,对于Oracle SELECT ROWS FROM TABELE WHERE ROWNUM <= 10看来,改变数据库和提供商不会帮助,不是吗?

2.实体框架。这个框架有转化为已选定DB statesment,这看起来忠实地仙丹内部独立的语言语句:

LINQ - >内部EF声明 - > MS SQL数据库,

LINQ - >内部EF声明 - > Oracle数据库。

那么,在传统的ADO.NET中,人们可以简单地更改数据库并且几乎独立于数据库吗?

回答

3

那么,在传统的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。

+0

如何,我们可以添加使用POCO类的在此处创建表的方法或生成创建表脚本? – ashy

0

盯着玩这个。我知道这是一个旧帖子。由于上面的例子很少修改。仍然有许多工作要做

using System.Collections.Generic; 
using System.Reflection; 
using Dapper; 
using System.Linq; 
using AppAttributes; 
using System.ComponentModel.DataAnnotations; 
using System; 

public abstract class DataModelBase 
{ 
    protected string _primaryKeyField; 
    protected List<string> _props = new List<string>(); 
    protected List<BuildClass> _class = new List<BuildClass>(); 

public DataModelBase() 
{ 
    PropertyInfo pkProp = this.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(KeyAttribute), 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); 
    } 

    foreach(PropertyInfo prop in this.GetType().GetProperties()) 
    { 
     if(prop.GetCustomAttributes<ExcludeAttribute>().Count<ExcludeAttribute>() > 0) continue; 
     MaxLengthAttribute maxLength = prop.GetCustomAttribute<MaxLengthAttribute>(); 
     MinLengthAttribute minLength = prop.GetCustomAttribute< MinLengthAttribute>(); 
     StringLengthAttribute stringLength = prop.GetCustomAttribute< StringLengthAttribute>(); 
     RequiredAttribute required = prop.GetCustomAttribute<RequiredAttribute>(); 
     RangeAttribute range = prop.GetCustomAttribute<RangeAttribute>(); 
     DataTypeAttribute dataType = prop.GetCustomAttribute<DataTypeAttribute>(); 
     KeyAttribute key = prop.GetCustomAttribute<KeyAttribute>(); 

     var kyk = prop.PropertyType; 
     //var sss = kyk.FullName.; 


     var cl = new BuildClass 
     { 
      Name = prop.Name, 
      MaxLength = maxLength != null 
      ? (int?)maxLength.Length 
      : stringLength != null 
       ? (int?)stringLength.MaximumLength : null, 
      MinLength = minLength != null 
      ? (int?)minLength.Length 
      : stringLength != null 
       ? (int?)stringLength.MinimumLength : null, 
      PrimaryKey = key != null ? true : false, 
      Type = prop.PropertyType.Name.ToString() 
     }; 
     _class.Add(cl); 
    } 
} 

[Exclude] 
public virtual string TableName { get { return this.GetType().Name; } } 

[Exclude] 
public virtual string InsertStatement 
{ 
    get { 
     return string.Format("INSERT INTO [{0}] ({1}) VALUES ({2})", 
      this.TableName, 
      GetDelimitedSafeFieldList(", "), 
      GetDelimitedSafeParamList(", ")); 
    } 
} 

[Exclude] 
public virtual string UpdateStatement 
{ 
    get { 
     return string.Format("UPDATE [{0}] SET {1} WHERE [{2}] = @{2}", 
      this.TableName, 
      GetDelimitedSafeSetList(", "), 
      _primaryKeyField); 
    } 
} 

[Exclude] 
public virtual string DeleteStatement 
{ 
    get { 
     return string.Format("DELETE [{0}] WHERE [{1}] = @{1}", 
      this.TableName, 
      _primaryKeyField); 
    } 
} 

[Exclude] 
public virtual string SelectStatement 
{ 
    get { 
     return string.Format("SELECT [{0}], {1} FROM [{2}]", 
      _primaryKeyField, 
      GetDelimitedSafeFieldList(", "), 
      this.TableName); 
    } 
} 

[Exclude] 
public virtual string CreateStatement 
{ 
    get { 
     return "CREATE TABLE " + TableName+" (" + GetDelimetedCreateParamList(",") 
      + ", CONSTRAINT PK_" 
      + _class.Where(c=>c.PrimaryKey).FirstOrDefault().Name 
      + " PRIMARY KEY(" 
      + string.Join(",", _class.Where(c=>c.PrimaryKey).Select(c=>c.Name)) + "))"; 
    } 
} 

protected string GetDelimetedCreateParamList(string delimeter) 
{ 
    return string.Join(delimeter, _class.Select(k => string.Format(" {0} {1} ({2}) {3}" + Environment.NewLine, 
     k.Name, 
     GetSqlType(k.Type), 
     k.MaxLength, 
     k.NotNull == true || k.PrimaryKey == true ? "NOT NULL " : "" 
     //k.PrimaryKey == true ? "PRIMARY KEY" : "" 

     ).Replace("()", "")) 
     ); 
} 

protected string GetSqlType(string type) 
{ 
    switch(type.ToUpper()) 
    { 
     case "INT16": 
      return "smallint"; 
     case "INT16?": 
      return "smallint"; 
     case "INT32": 
      return "int"; 
     case "INT32?": 
      return "int"; 
     case "INT64": 
      return "bigint"; 
     case "INT64?": 
      return "bigint"; 
     case "STRING": 
      return "NVARCHAR"; 
     case "XML": 
      return "Xml"; 
     case "BYTE": 
      return "binary"; 
     case "BYTE?": 
      return "binary"; 
     case "BYTE[]": 
      return "varbinary"; 
     case "GUID": 
      return "uniqueidentifier"; 
     case "GUID?": 
      return "uniqueidentifier"; 
     case "TIMESPAN": 
      return "time"; 
     case "TIMESPAN?": 
      return "time"; 
     case "DECIMAL": 
      return "money"; 
     case "DECIMAL?": 
      return "money"; 
     case "bool": 
      return "bit"; 
     case "bool?": 
      return "but"; 
     case "DateTime": 
      return "datetime"; 
     case "datetime?": 
      return "datetime"; 
     case "double": 
      return "float"; 
     case "double?": 
      return "float"; 
     case "char[]": 
      return "nchar"; 


    } 
    return "UNKNOWN"; 
} 

private string CreateField(BuildClass column) 
{ 
    return " " + column.Name + " " + column.Type + " (" + column.MaxLength + ") "; 
} 

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 BuildClass 
{ 
    public string Name { get; set; } 
    public string Type { get; set; } 
    public bool PrimaryKey { get; set; } 
    //public bool ForeignKey { get; set; } 
    public int? MinLength { get; set; } 
    public int? MaxLength { get; set; } 
    public bool NotNull { get; set; } = false; 

}