Entity Framework的原理及使用方式2011-06-03 14:25:33| 分類(lèi): 默認(rèn)分類(lèi) | 標(biāo)簽: |字號(hào)大中小 訂閱 ADO.NET Entity Framework操作數(shù)據(jù)庫(kù)的過(guò)程對(duì)用戶(hù)是透明的(當(dāng)然我們可以通過(guò)一些工具或方法了解發(fā)送到數(shù)據(jù)庫(kù)的SQL語(yǔ)句等)。我們唯一能做的是操作EDM,,EDM會(huì)將這個(gè)操作請(qǐng)求發(fā)往數(shù)據(jù)庫(kù)。 Entity Framework實(shí)現(xiàn)了一套類(lèi)似于ADO.NET2.0中連接類(lèi)(它們使用方式相同,,均基于Provider模式)的被稱(chēng)作EntityClient的類(lèi)用來(lái)操作EDM,。ADO.NET2.0的連接類(lèi)是向數(shù)據(jù)庫(kù)發(fā)送SQL命令操作表或視圖,而EntityClient是向EDM發(fā)送EntitySQL操作Entity,。EntityClient在EntityFramework中的作用是相當(dāng)重要的,,所有發(fā)往EDM的操作都是經(jīng)過(guò)EntityClient,,包括使用LINQ to Entity進(jìn)行的操作。 各種使用方式總結(jié)上文提到對(duì)EDM的操作,,首先通過(guò)一個(gè)圖來(lái)展現(xiàn)一下目前我們可用的操作的EDM的方式:
這幾種訪(fǎng)問(wèn)方式使用介紹如下:(部分示例代碼來(lái)源MSDN Magzine)
string city = "London"; using (EntityConnection cn = new EntityConnection("Name=Entities")) { cn.Open(); EntityCommand cmd = cn.CreateCommand(); cmd.CommandText = @"SELECT VALUE c FROM Entities.Customers AS c WHERE c.Address.City = @city"; cmd.Parameters.AddWithValue("city", city); DbDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess); while (rdr.Read()) Console.WriteLine(rdr["CompanyName"].ToString()); rdr.Close(); }
在有EntityClient+EntitySQL這種使用方式下,,使用ObjectService+EntitySQL的方式是多此一舉,不會(huì)得到任何編輯時(shí)或運(yùn)行時(shí)的好處,。在ObjectContext下使用EntitySQL的真正作用是將其與LINQ to Entity結(jié)合使用,。具體可見(jiàn)下文所示。 示例代碼: string city = "London"; using (Entities entities = new Entities()) { ObjectQuery<Customers> query = entities.CreateQuery<Customers>( "SELECT VALUE c FROM Customers AS c WHERE c.Address.City = @city", new ObjectParameter("city", city) );
foreach (Customers c in query) Console.WriteLine(c.CompanyName); }
string city = "London"; using (Entities entities = new Entities()) { var query = from c in entities.Customers where c.Address.City == city select c;
foreach (Customers c in query) Console.WriteLine(c.CompanyName); } 方式二: string city = "London"; using (Entities entities = new Entities()) { var query = entities.Customers.Where(r => r.Address.City == city);
foreach (Customers c in query) Console.WriteLine(c.CompanyName); } 這兩段示例代碼中的entities.Customer的寫(xiě)法隱式調(diào)用了2中示例的ObjectQuery<Customers>來(lái)進(jìn)行查詢(xún)(關(guān)于此可以參見(jiàn)EDM的設(shè)計(jì)器文件-xxx.designer.cs),。在方式二中的Where方法傳入的是一個(gè)Lambda表達(dá)式,,你也可以傳入一條EntitySQL語(yǔ)句做參數(shù)來(lái)將LINQ與EntitySQL結(jié)合使用。如下代碼演示其使用: string city = "London"; using (Entities entities = new Entities()) { var query = entities.Customers.Where("r.Address.City = '"+city+"'");
foreach (Customers c in query) Console.WriteLine(c.CompanyName); } 使用技巧及需要注意的問(wèn)題這也是上文提到的在ObjectContext下使用EntitySQL的一個(gè)主要作用,,上面的例子比較簡(jiǎn)單可能看不到這樣使用的優(yōu)勢(shì),,但是如下兩種情況下使用EntitySQL可能是最好的選擇。
這個(gè)并不是只能使用EntitySQL來(lái)實(shí)現(xiàn),LINQ to Entity也可以很容易完成,。如下代碼:
同理,,"V%"、"%V"可以分別使用StartsWith()與EndsWith()函數(shù)實(shí)現(xiàn),。
使用LINQ to Entity需要注意的一個(gè)方面是,,在完成查詢(xún)得到需要的結(jié)果后使用ToList或ToArray方法將結(jié)果轉(zhuǎn)變?yōu)閮?nèi)存中的對(duì)象,然后使用LINQ to Objects來(lái)處理,,否則處在Entity Framework的聯(lián)機(jī)模式下對(duì)性能有很大的影響,。
幾種方法的性能分析及使用選擇首先用下圖來(lái)說(shuō)明一個(gè)執(zhí)行過(guò)程。
圖中所示表達(dá)的意思已經(jīng)非常清楚,,稍加解釋的是,,無(wú)論是通過(guò)EntityClient直接提供給Entity Client Data Provider的Entity SQL還是通過(guò)ObjectService傳遞的Entity SQL(或是LINQ to Entity),都在Entity Client Data Provider中被解釋為相應(yīng)的Command Tree,,并進(jìn)一步解釋為對(duì)應(yīng)數(shù)據(jù)庫(kù)的SQL,。這樣來(lái)看使用LINQ to Entity與Entity SQL的效率應(yīng)該差不多,但是還有一個(gè)問(wèn)題,,那就是EntitySQL所轉(zhuǎn)換的最終SQL可能要比LINQ to Entity生成的SQL效率高,,這在一定程度上使兩者效率差增大,但是LINQ to Entity有其它技術(shù)無(wú)法比擬的好處,,那就是它的強(qiáng)類(lèi)型特性,,編輯時(shí)智能感知提醒,,編譯時(shí)發(fā)現(xiàn)錯(cuò)誤,這都是在一個(gè)大型項(xiàng)目中所需要的,。雖然現(xiàn)在也有了調(diào)試EntitySQL的工具,,但其與強(qiáng)類(lèi)型的LINQ to Entity還是有很大差距。 另外在ObjectService與直接使用EntityClient問(wèn)題的選擇上,。如果你想更靈活的控制查詢(xún)過(guò)程,,或者進(jìn)行臨時(shí)查詢(xún)建議選擇EntityCLient,如果是操作數(shù)據(jù)那只能采用ObjectService,。
上文總結(jié)了各種操作EDM的方式,,下面引用MSDN的一個(gè)對(duì)這幾種技術(shù)進(jìn)行比較的表格:
通過(guò)這個(gè)表可以很好對(duì)某一場(chǎng)合下應(yīng)該選擇的技術(shù)進(jìn)行判斷。EntityClient 和實(shí)體 SQL可以進(jìn)行最大的控制,,而使用LINQ to Entity可以獲得最佳的編輯時(shí)支持,。
其它操作EDM的方式通過(guò)EdmGen更靈活的控制EDM 在.NET Framework 3.5的文件夾下有一個(gè)名為EdmGen的工具,Visual Studio的實(shí)體設(shè)計(jì)器就是調(diào)用這個(gè)工具來(lái)完成EDM的生成等操作,。通過(guò)直接使用這個(gè)工具的命令行選項(xiàng)我們可以進(jìn)行更多的控制,。 這個(gè)命令的參數(shù)及作用如下:
使用示例: 從 Northwind 示例數(shù)據(jù)庫(kù)生成完整 Entity Model,。
從 ssdl 文件開(kāi)始生成 Entity Model,。
驗(yàn)證 Entity Model。
為什么要使用Entity Framework,,限制條件及當(dāng)前版本框架的問(wèn)題
通過(guò)對(duì)比上面圖4與圖2,、圖3我們可以很清楚的看到使用Entity Framework一個(gè)很大的好處,我們可以把實(shí)體類(lèi)的定義由一個(gè)單獨(dú)的項(xiàng)目使用C# class完成這樣一種設(shè)計(jì)方式轉(zhuǎn)變?yōu)槭褂脁ml文件定義并集成到數(shù)據(jù)訪(fǎng)問(wèn)層,。 在以往要在一個(gè)項(xiàng)目中動(dòng)態(tài)創(chuàng)建實(shí)體,,我所知的方法是把要添加的實(shí)體放入一個(gè)程序集,然后通過(guò)反射加載程序集?,F(xiàn)在可以通過(guò)動(dòng)態(tài)更改EDM的方法來(lái)增加實(shí)體并將其映射到數(shù)據(jù)庫(kù),,后者是以前無(wú)法實(shí)現(xiàn)的。 便于更改數(shù)據(jù)庫(kù),,當(dāng)更換數(shù)據(jù)庫(kù)后,,只需修改SSDL的定義,(如果數(shù)據(jù)庫(kù)的表明有變動(dòng),,也只需多修改MSL),,對(duì)CSDL沒(méi)有任何影響,,從而也不需要對(duì)程序的BLL等上層部分做任何改動(dòng)。
要想讓一個(gè)數(shù)據(jù)庫(kù)支持Entity Framework,,一個(gè)必要條件就是該數(shù)據(jù)庫(kù)需提供相應(yīng)的Entity Client Data Provider,,這樣才能將Entity SQL轉(zhuǎn)換為針對(duì)此數(shù)據(jù)此數(shù)據(jù)庫(kù)的SQL并交由ADO.NET來(lái)執(zhí)行。當(dāng)然該數(shù)據(jù)庫(kù)還需要提供ADO.NET Data Provider,。
Entity Framework技術(shù)的效率問(wèn)題是其幾乎唯一一個(gè)稍有不足之處,。首先其將EntitySQL轉(zhuǎn)換為SQL的方式屬于解釋性轉(zhuǎn)換,性能較差,。另外Entity Framework在每次應(yīng)用啟動(dòng)時(shí)需要讀取EDM,,這個(gè)過(guò)程較慢(但在后續(xù)操作時(shí),就不再存在這個(gè)問(wèn)題),。
EDM中的DML由于當(dāng)前的EntitySQL不支持DML操作,,所以當(dāng)前版本的Entity Framework的插入、更新及刪除操作需要通過(guò)Object Service來(lái)完成,。在EDM的設(shè)計(jì)器文件xxx.designer.cs中自動(dòng)生成了一些簽名為 void AddToEntity(EntityType entity) 的方法,。我們只需要新建一個(gè)實(shí)體對(duì)象并調(diào)用這個(gè)方法添加實(shí)體即可。注意這個(gè)函數(shù)內(nèi)部調(diào)用 entities.AddObject("EntitySetName", entity); 最后調(diào)用entities.SaveChanges()方法將修改保存回?cái)?shù)據(jù)庫(kù),,這是所有三種更新操作所需的,。更新與刪除操作都需要先使用ObjectService定位操作的實(shí)體對(duì)象,更新操作直接使用賦值運(yùn)算符,,刪除操作則調(diào)用 entites.DeleteObject(object o); 方法,。之后調(diào)用entities.SaveChanges()方法保存,這個(gè)過(guò)程簡(jiǎn)單,,不再贅述,。
含有Association的EDM的使用當(dāng)前版本的Entity Framework不支持自動(dòng)延遲加載,所有當(dāng)前未使用的關(guān)系中的相關(guān)實(shí)體默認(rèn)按不加載處理,,當(dāng)我們需要通過(guò)關(guān)系獲取一個(gè)實(shí)體對(duì)象時(shí),,我們可以采用兩種方法:
using (Entities entities = new Entities()) { var query = (from o in entities.Orders where o.Customers.CustomerID == "ALFKI" select o); foreach (Orders order in query) { if (!order.CustomersReference.IsLoaded) order.CustomersReference.Load(); Console.WriteLine(order.OrderID + " --- " + order.Customers.CompanyName); } }
using (Entities entities = new Entities()) { var query = (from o in entities.Orders.Include("Customers") where o.ShipCountry == "USA" select o);
foreach (Orders order in query) Console.WriteLine(order.OrderID + " --- " + order.Customers.CompanyName); } 查詢(xún)中針對(duì) Orders 實(shí)體調(diào)用的 Include 方法接受了一個(gè)參數(shù),,該參數(shù)在本示例中將要求查詢(xún)不僅要檢索 Orders,,而且還要檢索相關(guān)的 Customers。這將生成單個(gè) SQL 語(yǔ)句,,它會(huì)加載滿(mǎn)足 LINQ 查詢(xún)條件的所有 Order 和 Customer,。 兩種加載關(guān)系實(shí)體的方式的選擇根據(jù):如果針對(duì)關(guān)系數(shù)據(jù)你只需做一到兩次查詢(xún),則使用顯示加載更高效,,如果要持續(xù)訪(fǎng)問(wèn)關(guān)系實(shí)體中數(shù)據(jù),,則使用預(yù)先加載,。
關(guān)系下的添加,更新與刪除與上述操作基本相同,,唯一需要注意的是刪除操作不支持級(jí)聯(lián)刪除,,需要手工遍歷所有的相關(guān)項(xiàng)并將其一一刪除。注意這里刪除操作不能使用foreach來(lái)遍歷需要?jiǎng)h除的關(guān)系實(shí)體,。取而代之的有兩種方法:
while (result.Order_Details.Count > 0) { // 刪除操作… }
最新補(bǔ)充Entity Framework在開(kāi)發(fā)中的應(yīng)用 – Entity Framework與控件.NET Framework提供了許多xxxDataSource控件,,如SqlDataSource,ObjectDataSource等,,這些數(shù)據(jù)源控件大大方便了我們的數(shù)據(jù)綁定操作,。不幸的是目前還沒(méi)有針對(duì)Entity Framework的數(shù)據(jù)源控件發(fā)布,但是將數(shù)據(jù)綁定到諸如ListBox,,Grrdview或DetailsView控件也是很簡(jiǎn)單的,。這源于使用ObjectContext操作返回的IQueryable<T>對(duì)象或是使用EntityClient查詢(xún)返回的ObjectQuery對(duì)象都實(shí)現(xiàn)了IEnumerable接口。這樣很容易將這些數(shù)據(jù)綁定到數(shù)據(jù)顯示控件,。更新操作可以按上文所述在相應(yīng)的時(shí)間處理函數(shù)中寫(xiě)更新EDM的程序即可,。 Entity Framework的鏈接字符串默認(rèn)情況下(Visual Studio對(duì)Entity Framework數(shù)據(jù)項(xiàng)目的默認(rèn)設(shè)置),EDM這個(gè)XML文件被作為資源在編譯時(shí)嵌入到程序集中,。這種情況下當(dāng)更改EDM后需要重新編譯這個(gè)程序集才能使更改生效,。通過(guò)更改項(xiàng)目屬性也可以讓EDM作為三個(gè)獨(dú)立的XML文件存在于項(xiàng)目中。為了讓?xiě)?yīng)用程序可以找到EDM(無(wú)論其以什么方式存儲(chǔ))需要一個(gè)鏈接字符串來(lái)指示EDM所在的位置,。實(shí)體模型設(shè)計(jì)器生成的鏈接字符串如下所示:
http://msdn.microsoft.com/zh-cn/library/cc716756.aspx 關(guān)鍵的一點(diǎn)應(yīng)用程序是怎樣找到這個(gè)字符串的,,對(duì)于使用EntityClient的情況,可 |
|
來(lái)自: orion360doc > 《.NET框架》