牛骨文教育服务平台(让学习变的简单)

实体框架一个基本的功能就是要与数据库交互,与数据库交互当然可以利用现有的一些基本技术,比如dotnet的ADO.Net等。这里有几个要点:

      1)要封装底层的数据库交互通道,这个可以利用现有的数据库访问技术,比如ADO.Net。

      2)构造与数据库交互的SQL语句,比如新增,删除,修改,查询等.做得比较好的,需要支持关联查询等。当然能做到AEF中的ESQL那样,还是有点难度。

下面是一个实例,这里我只构造插入语句,并实现现数据库插入实体的功能示意(底层数据库访问封装这里不讲,这个有很多例子)。

为了简单起见,我们假设实体类的类名就是数据库里对应表的表名,实体的属性对应数据库表里的字段,下面就是代码:

       //实体类。  
       public class AModel  
       {  
           public string Field1{get;set;}  
           public string Field2 { get; set; }  
           public int age { get; set; }  
           public string Name { get; set; }  
       }  
       /// <summary>  
       /// SQL语句执行,可以采用普通类,也可以采用抽象接口,便于不同数据库的访问.  
       /// </summary>  
       public static  class DatabaseHelper  
       {  
           public static void ExecuteSQL(string strSQL, SqlParameter[] Params)  
           {  
               ;//......................  
           }  
       }  
       /// <summary>  
       /// 实体数据库基本操作,这里只是模拟实体插入数据库的情形,其它的操作其实类似,更新的话可以采用关键字做条件,冲突检查字段也可包含在条件里面.  
       /// </summary>  
       public static class DbOperation  
       {  
           public static void InsertModel<T>(T Model)  
           {

               //这里的sql语句及参数构造结果可以采取缓存方式,没必要每次都去构造,以减少性能损失。  
               Dictionary<string,string> thePP = new Dictionary<string,string>();  
               Dictionary<string, SqlDbType> thePT = new Dictionary<string, SqlDbType>();  
               string theSQL = SQLBuilderHelper.BuilderInsertSQL<T>(thePP,thePT);  
               List<SqlParameter> theParams = new List<SqlParameter>();  
               foreach (var item in thePP)  
               {  
                   SqlParameter theP = new SqlParameter();  
                   theP.SqlDbType = thePT[item.Key];  
                   theP.ParameterName = item.Value;  
                   theP.Value = GetPropertyValue(Model, item.Key);  
                   theParams.Add(theP);  
               }  
               DatabaseHelper.ExecuteSQL(theSQL.ToString(), theParams.ToArray());

           }

           //根据属性名获取属性值,可以单独放在一个辅助类里。  
           private static object GetPropertyValue<T>(T Model, string PropertyName)  
           {  
               Type theType = Model.GetType();  
               PropertyInfo pi = theType.GetProperty(PropertyName);  
               return pi.GetValue(Model, null);  
           }  
       }  
       /// <summary>  
       /// SQL及参数构建器,这里构造sql语句的时候,**在这里,默认类名就是数据库表名,属性名就是数据库字段名。但在实际构造这种框架的时候,可以采用元属性或者配置文件来实现这个功能**。比如linqtosql,DbContext就采用元属性,AEF,Hibernate就是采用xml格式的配置文件,但这些东西都是为了更好更准确的构造sql语句.构造这种

       ///sql语  句    需要知道的包括表名,字段名,字段类型,语言类型与字段类型间的对照等。  
       /// </summary>  
       public class SQLBuilderHelper  
       {  
           public static string BuilderInsertSQL<T>(Dictionary<string, string> PropertyAndParams,Dictionary<string,SqlDbType> thePAndDBType)  
           {  
               Type theType = typeof(T);  
               PropertyInfo[] theProperties = theType.GetProperties();  
               StringBuilder theSQL1 = new StringBuilder();  
               StringBuilder theSQL2 = new StringBuilder();  
               PropertyAndParams.Clear();  
               //其实这里也可以利用元属性来觉得哪些需要属性需要插入,哪些属性只能读取之类的判断,以及更新模式(对数字类型是赋值更新还是增量更新)等。  
               foreach (var p in theProperties)  
               {  
                   if (theSQL1.ToString() == "")  
                   {  
                       theSQL1.Append(p.Name.ToUpper());  
                       theSQL2.Append("@" + p.Name.ToUpper());  
                   }  
                   else  
                   {  
                       theSQL1.Append(","+p.Name.ToUpper());  
                       theSQL2.Append(",@" + p.Name.ToUpper());  
                   }  
                   PropertyAndParams.Add(p.Name, "@" + p.Name.ToUpper());  
                   thePAndDBType.Add(p.Name, GetDbType(p.PropertyType));

               }  
               return "INSERT INTO " + theType.Name.ToUpper() + "(" + theSQL1.ToString() + ") VALUES(" + theSQL2.ToString() + ")";  
           }

           //C#类型与数据库类型的对照可以通过Map文件完成,也可以通过元属性完成,个人觉得元属性的利用比较好,虽然说元属性不是很灵活,

           //但减少了构造的文件依赖,        在大型的项目中其实是有好处的,至少是便于管理的。  
           private static SqlDbType GetDbType(Type type)  
           {  
               if (type == typeof(int))  
               {  
                   return SqlDbType.Int;  
               }  
               return SqlDbType.NVarChar;  
           }  
       } 

有的时候我们将实体对象称之为概念模型,而对象在数据库里的存储结构称之为物理模型,在这两个模型之间存在着一种映射关系(概念名称与物理名称的映射,对象属性与字段名之间的映射,以及对象之间关系的映射),这其实就是所谓的ORM(对象关系模型)。上面的例子这种映射是利用命名规范来完成,实际上做的时候可以采用配置文件或者元属性来完成,对于大项目时,配置文件的管理本身也会成为一个问题,因此我觉得用元属性数据来进行会比较好。

上面的实现只是一个简单的示例,实际做的时候需考虑得东西会比较多,比如需要封装数据库差异(底层访问差异,sql语句方言),实体与数据库之间的对照(map),SQL语句及参数缓存问题(没必要每次都构造)等,但不管怎么说,基本的原理还是一样的,关键技术主要是反射机制的应用。

下一篇,将介绍实体管理的功能,比如缓存,加载,新增,删除等....