请注明转载地址:http://www.cnblogs.com/arhat
这篇文章老魏和大家分享一下Entity Framework的CRUD操作,在这之前呢,老魏先说一下老魏对EF的一个整体的认识,当然如果有不对的地方希望大家能够提出来,我们来一起的讨论一下。
老魏在经历了NHibernate这个ORM框架之后接触了EF这个在.NET平台上迟来的自家的ORM框架,从整体上看,其实这两个ORM框架的思想倒是很多是一样的,但是在使用了EF后,再发现有很多的操作比起NHibernate要强了不少,但是同时也暴露出了很多的问题,这些问题是老魏目前比较头疼的问题,到现在都没找到一个合适的解决方法,只能是希望EF在后续的版本中能够解决这些问题。
在EF查询的时候,其中有一个最让人蛋疼的问题就是不能够把匿名对象交给其他域访问,也就是匿名对象跨域访问的问题,当然在网络上有一些解决方法,但是老魏老是感觉不是很好,在老赵的一片文章中虽然提供了一个比较不错的方法,但是使用起来时比较的麻烦的,哎,只能说到现在老魏也是在头疼这个问题。
在EF中如果使用linq的分组的时候,需要用到两次的foreach循环,而且更让人蛋疼的设计是竟然在group的时候懒加载竟然不能使用,如果使用的话竟然报了一个“There is already an open datareader accociated width this Connection which must be closed first”的错误,很是无语啊。当然这个问题很有可能和数据的设置有关系,在后面的章节中老魏会来讨论一下这个问题。
同时在EF中,微软给出了两个查询的方案,一个是使用Linq to Entity另外一个是EQL。当然看到这里可能大家会迷糊(老魏也曾迷惑过),那么在使用EF的时候是使用linq呢还是EQL呢?其实这个问题我们很好回答,迷糊的原因是微软提供了多个解决方案而已,用的时候根据个人的爱好选择使用。一般情况下,如果遇到复杂SQL语句,ling无法解决的时候就需要EQL了。老魏认为微软太为程序员着想了,弄的程序员都得学习,其实这点就不如NHibernate了,只提供一个HQL语句,用不用就看你了。所以说啊,微软有时候这好人做的确实是有点过了。
不过怎么说呢,在使用EF的时候说实在的的确要比NHibernate要方便的多了,不用再配那么多的映射文件了。
好了,上面就是老魏对EF的人是,如果各位网友有更好的建议可以为老魏提出来。下面我们就开始今天的章节吧。
接着上一节内容,在上一节中我们对School这个数据进行了EF Db Fist了。那么现在我们就要使用这个EF来操作这两个表了,当然在后面的章节中老魏会添加一张Course(课程)表用来学习查询的相关的学习。
首先测试,虽然我们建立了三层的架构,但是为了测试方便我们在主项目Test中添加对DAL和Model的引用。
首先呢,我们为课程添加记录,在Program.cs文件中我们更改代码如下:
static void Main(string[] args) { //上下文对象 DAL.SchoolContext context = new DAL.SchoolContext(); //创建一个clazz对象 Model.Clazz clazz = new Model.Clazz() { CName="测试课程" }; //把clazz加入到ObjectSet中,但是此时并没有插入到数据库 context.Clazz.AddObject(clazz); //更新数据库,这时才真正的吧clazz加入到了数据中 context.SaveChanges(); }
那么现在我们执行一下,发现没有任何的问题,打开数据库查看一下:
看来我们正确的把数据插入到数据库中。对于上面的代码老魏得解释一下,因为有很多东西并不是我们所了解的,大部分的代码都是有EF给我生成的。
首先是SchoolContext这东西。这个东西是至关重要的一个东西了,称之为数据上下文对象。我们操作数据库就是靠这个东西的。从SchoolContext的继承关系上,我们知道它继承了ObjectContext(对象上下文)。其实这点才是老魏迷糊的地方,记得官方说的EF6默认使用的DbContext,可这里VS2010使用的ObjectContext了,老魏没有找到原因,还有一个可能就是老魏使用的是MySql数据,难道老魏装的MySql Connector不支持EF6吗?不可能啊,官方说的是可以支持的。其实最后老魏发现,原来老魏用的T4模板中是用的ObjectContext的。不过无所谓了,原理都一样的,那我们先使用ObjectContext吧。到后面的章节中老魏得想办法用VS2013的,这样就回跟上了。
ObjectContext是Entity Framework封装了数据库访问的上下文,以及实体的映射关系元数据信息等。EF帮我们封装好了这么一个统一的接口。让我们所有的操作都只通过这个一个实体上下文就可以实现了增删查改等所有对应数据库的操作。我们查看一下ObjectContext的定义:
不知道大家从图上看到了什么,红色部分能够帮我们了解ObjectContext的本质是什么,从红色的部分知道了ObjectContext为什么能够帮我们连接数据库了,其实还是通过connectionString,DbConnectgion这些传统的ADO.NET的知识来连接的。但是ObjectContext是不可能只做这写事,如果是这样的话那么EF也就太弱了吧(哈哈)。当我们使用Model First的时候,为什么为自动的创建数据?原因大家已经看到了,在ObjectContext中有一个CreateDataBase的方法,同时还有一个CreateObject的方法,这个方法我想就不需要解释了吧。
需要注意的是黄色的部分才是比较重要的地方,在我们的SchoolContext中我们发现有这样的属性:
public ObjectSet<Model.Clazz> Clazz { get { return _clazz ?? (_clazz = CreateObjectSet<Model.Clazz>("Clazz")); } }
而这个属性是ObjectSet类型的,那么ObjectSet有一个是什么东东呢?根据微软的解释“ObjectSet表示模型的实体集”。那么很显然了ObjectSet是一个集合。当然了ObjectSet不仅仅是一个实体集而已了,它同时提供了对实体集的用于执行创建、读取、更新和删除操作,这也就是我们context.Clazz.AddObject(clazz)通过这句话来添加实体对象了。
这个是ObjectSet的定义,我会发现它的确是提供了很多方法能够操作实体集。其实说到这里呢,各位不知道有没有一些发现呢?通过对比的话,我们能够更简单易懂的理解ObjectContext和ObjectSet了。下面老魏来画张图来说明这两个对象和数据库之间的关系。
从图上我们可以这样来理解,DataBase(数据库)对应一个ObjectContext(DbContext),只不过ObjectContext(DbContext)封装了一些列操作数据的方法,功能强大了。然而DataBase中的每个表都可以认为是ObjectSet对象,一个表就是一个ObjectSet,其实很容易的理解,一个表有多个记录,每个记录就是一个实体,而这些实体是不是存放在表中的而是ObjectSet中的。同样的,ObjectSet不仅仅只是用来存储实体的,还提供操作实体的方法,功能也强大啊!
通过上面的解释,老魏相信大家应该对ObjectConext(DbContext)和ObjectSet有一些了解了吧,希望能够帮助大家。
好了,这两个对象已经给家讲过了,下面就继续本章的内容。刚才我们只是在clazz表中添加了一条记录,删除和编辑我们来做一下。
更改一下Program.cs的代码,我们来删除一条记录:
static void Main(string[] args) { //上下文对象 DAL.SchoolContext context = new DAL.SchoolContext(); //得到一个clazz对象 Model.Clazz clazz = context.Clazz.Where<Model.Clazz>(c => c.CId == 12).FirstOrDefault<Model.Clazz>(); //把clazz从ObjectSet中删除,并咩有真正的删除 context.Clazz.DeleteObject(clazz); //更新数据库,这时才真正的吧clazz从数据库中删除 context.SaveChanges(); }
这里老魏不得不说了,在删除的时候EF要求先去查询一下这个数然后才能删除,这样的话我们就回打开两次数据库了,从性能上说是非常不好的,但是微软的这种考虑是值得思考的,在项目中我们删除数据的时候很有可能是判断这条数据存不存在,如果存在则删除。其实这种需求是存在。但是如果不想这样先查询在删除的话,也是可以的,这个问题将在下一章节在阐述吧。
同理,我们再更改一下Program.cs来编辑一条记录吧,从上面的删除的过程我们就可以推测出肯定也是先查询然后再更改的。
static void Main(string[] args) { //上下文对象 DAL.SchoolContext context = new DAL.SchoolContext(); //得到一个clazz对象 Model.Clazz clazz = context.Clazz.Where<Model.Clazz>(c => c.CId == 11).FirstOrDefault<Model.Clazz>(); //更新CName值,并咩有真正的在数据中更新 clazz.CName = "ASP.NET MVC学习班"; //更新数据库,这时才真正的吧clazz从数据库中更新 context.SaveChanges(); }
到此呢,本章基本就要结束了,在实现了CRUD之后呢,值得我们思考的是EF虽然给我们带来了方便,但是底层的东西还是要会的,当然老魏值得是ADO.NET。其实在项目中还是ADO.NET用的居多啊。
不知道看过这章的网友有没有收获呢,如果有的话老魏是非常高兴的。在提供我自己的同时也帮到了大家,真是应了那句话”独乐了不如众乐乐”。