請注明轉載地址: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用的居多啊。
不知道看過這章的網友有沒有收獲呢,如果有的話老魏是非常高興的。在提供我自己的同時也幫到了大家,真是應了那句話”獨樂了不如眾樂樂”。