(6)—总结

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

1、实体应该要简单,层次最好平面化,这样有利于实体在各种通信中穿越(比如Webservices,WCF,Remoting,WCF RIA等); 2、虽然实体应该平面化,但并不代表不能有继承层次,因为这种层次可以获得很多管理和架构的好处 但要注意两点:       1是尽量采用接口,而且接口的方法或属性主要目的是提供统一访问实体的标准接口       2是属性的代码不要复杂,不要对外依赖,而方法更应该如此,能在操作类或者其它辅助类完成的尽量不要安排在实体类完成。     在整个架构体系中,实体类和系统定义的枚举等常量一样,应该处于引用的最底层,也就是实体类库原则上不引用你自己      定义的其它类库(当然,如果你把系统的常量定义,枚举定义等系统规范性定义放在一个类库,实体类库还是可以引用)。 3、采用根据实体(包括配置文件)动态构造SQL的方式与数据库交互,虽然大量的减少了数据访问和转换类,但也失去了很多灵活性,      如果关系数据库处理更加专业,那还是留给关系数据库去处理。 4、无论什么框架,数据从界面到数据库,该干的事情一件不能少,只是方式不同而已      实体框架提供的数据库访问功能,大部分都可以利用AutoCode工具自动生成,至于缓存,很多时候还是需要你自己去维护一部分。 5、成本的减少不是靠一个框架能解决,如果选择不当,反而会增加成本。      包括实体框架的学习成本,跟随成本,一些问题不太好解决的时候,曲线救国的成本等。 6、虽然没必要从汇编开始做起,但在可选的范围内,尽量使用较为原始的方式处理会根据持久性。      这主要是针对实体框架的劣势而言。 7、造船与租船:对于个人选哪个都可以,但对于国家则需要鼓励造船而不是租船。对于企业,在中国目前的氛围下,不做讨论。 8、项目管理者根据需要造或租,但作为程序员,还是多知道点造的技术为好; 9、虽然做技术不一定赚钱,赚钱不一定要技术,但做程序员还是要关注点技术,因为这至少暂时是你工作的需要。 整体上来讲,如果是项目的规模不是很大,可预见的业务关系不是很复杂,而且公司也不打算走产品路线,那么采用成熟的实体框架 应该是优先的选择;如果是个人搞一些系统,那当然是“拿来主义”至上。 在选择实体框架产品的时候,就我个人的观点,最好不要用微软的东西,虽然强大,但夹带的私货太多。 后记:在一个几乎人人都想一夜暴富的国度,谈技术都有些不合时宜....但惩罚却要开始了... 用市场没有换来值钱的技术,却换来了一堆连厕纸都不如的国债...道指暴泄,杯具的却是我们这些屁民, 奈何?
';

(5)–给实体管理类增加一点特色

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

~~~    /// <summary>    /// 扩展实体管理类    /// </summary>    public static class EntityMgmtExtension    {        public static IEnumerable<T> Select<T>(this EntityMgmt<T> mgt, Selector<T> Selector)        {            return mgt.GetEntities(Selector);        }    } ~~~ 一个简单的扩展方法,实际上NetFramework中的Where,Select,OrderBy,Join都是利用这种方式实现的,而Linq技术的本质也是这样实现的,只不过它采用了 类似于sql的语法。这个方式只能由编译器才能完成。 这篇的目的其实是为了说明,很多技术看起来很酷,但实际上并没有什么很特别的东西,学习要尽量了解其本质,而不要为了它的一些语法糖而迷失自己。 很多技术,很多概念其实就是别人给我们的一些羊皮,但我们乐此不疲的陷入这种扯羊皮的而不知追求更本质的东西时,看起来很傻的人却在得意的看着我们。 微软就是这样的,它的很多东西,都有这样的影子。比如微软的补丁,有的确实是需要补,但有些补丁却是为了让我们乐于补而补。 这个世界不仅仅有技术,还有利用技术做武器的商术,政术.....
';

(4)–实体的管理

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

实体的管理主要包括如下功能: A) 实现实体的缓存; B) 实现实体的新增,修改,删除,查询等功能; C)刷新缓存与数据库同步 D)  将缓存语句与数据库同步 上面是一些基本的功能,下面是一个基本示例: ~~~ //实体状态,对于实体采用缓存方式时有用。 public enum EntityState    {        NoChanging,        Added,        Modified,        Deleted    } //这个类是真正实体的容器,目的是为了附加一些信息,便于实体的管理。    public class EntityItem<T>    {        public T StorageItem{get;set;}        public T CurrentItem{get;set;}        public T OrigialItem{get;set;}        public EntityState State{get;set;}        public EntityItem()        {        }    }   //利用委托,将选择等工作交给用户自己决定。    public delegate bool Selector<T>(T M);    //实体管理类,需要提供数据库连接管理,实体加载,查询,新增,删除,修改,与数据库同步等功能    //另外也需要提供事务支持功能,支持事务时需要提供能传入连接和事务实例的构造功能。    //或者本身实现事务,自我回滚,并抛出异常,这样可以实现多个管理类之间的任意组合式事务处理。    public class EntityMgmt<T>    {       //实体集合        private List<EntityItem<T>> _entities;        private string _connString;        public EntityMgmt():this("")        {                   }        public EntityMgmt(string Conn)        {            _entities = new List<EntityItem<T>>();            _connString = Conn;            if (_connString == "")            {                //LoadFromConfigurationFile            }        }        private void LoadEntities()        {            //构造查询SQL,加载实体,可参见与数据库交互部分.        }        //提供查询功能        public IEnumerable<T> GetEntities(Selector<T> Selector)        {            List<T> theRets = new List<T>();            if (_entities.Count <= 0)            {                LoadEntities();            }            for (int i = 0; i < _entities.Count; i++)            {                if (_entities[i].State!= EntityState.Deleted && Selector(_entities[i].CurrentItem) == true)                {                    theRets.Add(_entities[i].CurrentItem);                }            }            return theRets.AsEnumerable();        }        //新增一个实体        public void Add(T Item)        {            EntityItem<T> theItem = new EntityItem<T>();            theItem.CurrentItem = Item;            theItem.OrigialItem = Item;            theItem.State = EntityState.Added;            _entities.Add(theItem);        }       //修改        public void Update(T Item, Selector<T> SelectOldItem)        {            EntityItem<T> theEntityItem = null;            for (int i = 0; i < _entities.Count; i++)            {                if (SelectOldItem(_entities[i].CurrentItem) == true)                {                    theEntityItem = _entities[i];                    break;                }            }            if (theEntityItem != null)            {                theEntityItem.CurrentItem = Item;                theEntityItem.State = EntityState.Modified;            }        }        //接受改变,并将变化同步到数据库.        public void AcceptChanges()        {            foreach (var item in _entities)            {                switch (item.State)                {                    case EntityState.Added:                        DbOperation.InsertModel<T>(item.CurrentItem);                        break;                    case EntityState.Deleted:                        break;                    case EntityState.Modified:                        //这里可以利用item.StorageItem做并发检测                        break;                }            }        }    }   public enum CacheType    {        AppLevel,        SessionLevel,        None    }    //用工厂模式实现对实体管理类的创建,这样的好处是可以在这里实现对实体管理类本身的管理:    //全局单例模式,Session级共享等.    //这个类也可以实现对某个实体管理工厂的单例模式    public static class EntityMgmtFactory    {        private static readonly Dictionary<Type, CacheType> _CacheTypes = new Dictionary<Type, CacheType>();        static EntityMgmtFactory()        {            //可以根据文件配置加载缓存方式.        }        public EntityMgmt<T> CreateEntityMgmt<T>(string conn)        {            //根据缓存类型来创建或获取实体管理类的实例。            //这里不再赘述。缓存级别可以利用Runtime的Session.            return new EntityMgmt<T>(conn);        }    } ~~~ ================================ 上面的示例只是一些基本的功能,在实际应用中需要考虑的会更为复杂,比如可以设置失效期,自动同步等。另外也需要提供直接执行SQL的功能等。 AEF的方式比较复杂,但基本原理差不多,它的ESQL确实比较强大,这是其它一般框架所不具备的,但所谓成也萧何败也萧何,提供如关系数据库般得功能, 结果把简单问题复杂化了,反而在缓存,复杂查询,自由SQL支持方面显得不足(对自由SQL的支持实际上是违背AEF框架的目标的)。
';

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

(2)–实体框架的基本功能

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

一般的实体框架都包括以下一些功能: ### 1、与物理存储交互 原因很简单,数据不能总在内存里,最终还是要存起来,所以,实体框架的一个基本功能就是要解决与物理存储之间的交互问题。这里的物理存储主要包括文件和数据库系统,以文件作为实体的物理存储方式,虽然不是很普遍,但也有用武之地,一些很小的应用系统,表不多,数据之间的关系不是很复杂的情况下,也可以直接采用文件进行存储,没必要为这种很小的应用还附带上一个数据库。就是采用了数据库,有些配置信息也可以放在文件中。 以数据库作为实体的物理存储方式,是目前应用系统普遍采用的一种方式,因此一般的实体框架都需要支持与数据库进行交互的功能:      A)支持多种数据库,至少要支持几种主流的数据库系统(屏蔽数据库差异);      B)支持对数据库的基本操作(定义,新增,修改,删除,查询等)      C)支持数据库事务      D)支持缓存与数据库之间的数据同步(这条不是必须,但好的框架至少要预留对这种需求的扩展). 2、对实体的管理 对实体的管理以下一些功能是基本的:     A)对实体的新增,修改,删除和查询并将这些操作最终反映到数据库;     B)SQL语句支持(有些事情无法完全针对实体完成的时候,还是要预留这种功能)     C)事务支持(最终要反映到数据库事务上来,好的还会支持跨数据事务)     D)实体缓存服务(包括是否需要缓存,缓存机制,失效策略等),如果更进一步,还应该支持数据缓存加载条件设置(这种功能其实很简单,但目前的很多框架都没有这种功能)     E) 支持缓存还必须提供缓存与数据库的数据同步机制;     F)如果支持缓存,也必须提供并发冲突检测和处理机制;     有些功能还提供一些更强大的功能:      A)实体高级查询,比如关联查询,子查询等。例如ESQL跟SQL就很相似。      B)实体操作的批处理。      C)实体操作类的单例、多例模式支持 上面列的基本都是实体框架应该提供的一些基本功能,还有一些实体有效性检查之类的功能,可以集成在这里,也可以不集成在这里,但一些规则性的东西还是需要提供,比如以元属性方式提供校验规则等。    
';

(1)–实体与操作类

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

### 1、什么是实体? 在我们进行系统构造的目标业务领域里,有一些对象,主要依赖外界进行管理或者处理,这些对象主要处在被加工或者处理的地位,这样的对象我们称之为实体对象,而这类对象以数据为住,一般只具有属性(或者叫域),不包含或只包含少量的内生方法(主要是一些自我处理的方法,这些方法不会操作其它对象,不产生对其它外界对象的依赖,比如克隆,格式化等)。直白的讲,实体就是数据性对象,结构体和类都可以用来描述它。实体类是允许嵌套的,即实体类的属性也可以是另外的实体类型(本身也可)。与实体类相对应的就是操作类(业务类,数据处理类等)。 ### 2、实体操作类 这里的操作类主要是指针对实体进行操作的类,这些操作类除了包含一些必要的用来指导操作方法的属性外,一般都不包含数据性属性。操作类包含的方法一般都是针对实体或者实体集合的。通常情况下,操作单个实体和操作实体集合的类会分开。操作单个实体的,比如格式显示,反射赋值,反射取值;而针对实体集合的则主要是新增,修改,读取,删除,查询,筛选,计数,统计等操作。实体操作类和业务处理类的区别就是实体操作类只针对实体类本身,不带业务逻辑色彩。从数据库的角度看,实体操作类就相当于数据库的sql. ### 3、实体为何要与操作分离 实体代表数据,操作代表处理数据的方法,这种将实体和实体操作分离是面向对象编程下一个比较明智的改变,一方面因为面向对象只是分析和设计的一个视角,并不代表世界的全部,传统的那种将数据和方法分离的模式(面向过程)还是有其优势的,特别是在大规模数据处理方面。其二,实体类与实体的操作方法,特别是外界施加给实体的方法,从逻辑上来讲也很难理解。我一直觉得,面向过程和面向对象并不是对立的,它们之间是对立和统一的,面向对象侧重于整体和全局性,面向过程则注重局部与实现。 实体类和操作的分离的好处:    1)便于存储、运输、共享和交换 一般情况下实体都是很简单的东西,因为不带有方法,而只有数据,因此便于存储,运输,共享和交互。有利于以XML格式进行处理。 2)便于操作复用 如果实体遵循一定的规则(大多时候用元属性来描述),很多对实体的处理操作都可以通用方法。比如实体的增加,删除,修改,查询等。 3)便于与文件系统和数据库系统的结合 我们知道文件系统和数据库系统存放的主要是数据,而对于这些数据的处理都是外界附加的。实体与操作的分离,实体就非常适合与结构话的文件数据和数据库数据进行 转换,便于在内存中实施对这些数据的处理。    4)以实体而不是单纯的记录来表示数据,可以很好的利用类的特性,来聚合数据,可以更好的从整体方面来对待这些对象,比如订单实体,可以将表单头和订单明细数据作为整体来考虑。 不好的地方:      1)因为实体只包含属性,而不提供或者只提供少量的方法,使得原来可以封装在实体对象内的方法,也必须由外部提供,而且实体必需全面暴露自己。从这个方面来看,站在面向对象的角度讲,破坏了对象的封装性。同时由于实体主要包含的是静态特征,多态,继承的作用不是很大(提供一定的接口属性实现还是可以的)。其实这算不上不好的地方,有些事情没必要进入“洁癖”状态。 看到这里,大家或许会发现,实体与操作类的分离,有点数据库的味道,实际上现在有些持久层框架在某种意义上来讲,就是一个简化的内存关系数据库,比较典型的就是LINQToSQL,ADONetEntity Framework。 ........ 下一篇,主要讲实体框架主要功能和一般架构,对于一些关键技术,会提供代码实现。 同时也欢迎大家指正。
';

对使用通用框架的一点看法.

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

      现在业界充斥着各种各样的框架,有持久层的,也有业务逻辑层的,在一些项目上应用这种框架,就短期成本而已,应该是一个很好的选择,但框架毕竟是框架,有利也必然有弊。框架的学习其实并不难,但我觉得作为程序员,应该不仅仅停留在使用这个层面,还应该更深入的了解一下这些框架的基本原理和机制,以丰富自己的知识体系,不要说有利于自己去架构,就是使用也有很大的好处。对于企业采用框架,从成本上来说,如果是项目型的,短期当然是有利的,这种区别其实也是造船和租船的区别,但如果企业要形成自己的核心产品,还是不要采用这些框架为好,因为框架不是基本的技术,更多的是一种应用。而且每种框架都有自己的优势和劣势,总会有更好的框架出现,你如何去跟随呢?而一旦遇到框架的瓶颈,就很难在原来框架上做修改,拐弯抹角的解决问题固然可以,但最种会使得系统变得很复杂,很难看,很难管理的。而且作为这些开源性的框架,往往都是面向大众,针对普遍应用的,而对于具体的企业而言,往往是取其几点,就必须拿其一面,何苦呢?从项目管理上来讲,开源框架也往往会成为一种扯羊皮的东西。有的东西到底是框架的问题还是其它程序的问题,很难扯得清。       总的来讲,我觉得在业务逻辑比较复杂的大型系统中,我觉得可控性和一体性是最重要的,而这些恰恰是使用这些开源框架的不利之处。
';

前言

最后更新于:2022-04-01 11:41:59

> 原文出处:[解剖实体框架](http://blog.csdn.net/column/details/frame.html) 作者:[田世权](http://blog.csdn.net/hawksoft) **本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!** # 解剖实体框架 > 框架的学习其实并不难,但我觉得作为程序员,应该不仅仅停留在使用这个层面,还应该更深入的了解一下这些框架的基本原理和机制,以丰富自己的知识体系,不要说有利于自己去架构,就是使用也有很大的好处。
';