(3)–与数据库交互

最后更新于:2022-04-01 11:42:08

实体框架一个基本的功能就是要与数据库交互,与数据库交互当然可以利用现有的一些基本技术,比如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语句及参数缓存问题(没必要每次都构造)等,但不管怎么说,基本的原理还是一样的,关键技术主要是反射机制的应用。 下一篇,将介绍实体管理的功能,比如缓存,加载,新增,删除等....
';