最近项目用到EF,开发遇到了很多问题,这篇文章深入探讨。本文虽是繁体,但是基本勉强看懂,相信代码和图大伙都懂的
原文如下:
在這邊分享跟介紹,使用ADO.Net Entity Framework時,一定會碰到的問題,
如何在ObjectContext間傳遞EntityObject並進行資料庫操作,
簡單說就是當你從一個ObjectContext取得一筆資料(EntityObject)後,
跨越另一個類別(Class)要再利用ObjectContext去操作剛剛取得的EntityObject,
例如要新增、修改、刪除、查詢等,要如何實做,
適用的情境像是在WebService、多層式架構、利用ObjectDataSource存取資料時等等,
都會遇到此問題。
在實作範例之前,有幾個重要觀念與名詞必須先介紹一下
不知道大家在使用ADO.Net Entity Framework取得一筆資料的時候,
有沒有發現除了欄位名稱轉換成屬性,還自動產生了多了兩個很重要的屬性【EntityKey】、【EntityState】,
因為EntityObject實作了IEntityWithChangeTracker介面,讓這些物件能夠報告變更,
簡單說明一下這些屬性
名稱 | 值 | 說明 |
EntityKey | EntitySet=User;User_id=3 | 提供實體 (Entity) 類型執行個體 (Instance) 之物件的持久參考。 |
EntityKey. | TestEntities (此為範例) | 取得實體容器的名稱。 |
EntityState | Detached | 雖然此物件存在,但是物件服務沒有追蹤此物件。在已經建立實體之後而在實體加入至物件內容之前,實體就會處於這種狀態中。在已經透過呼叫 Detach 方法從內容中移除實體,或者使用 NoTrackingMergeOption 載入實體時,實體也會處於這種狀態中。 |
Unchanged | 自從此物件載入內容中,或者自從上一次呼叫 SaveChanges 方法以來,此物件就沒有修改過。 | |
Added | 此物件已加入至物件內容,而且尚未呼叫 SaveChanges 方法。物件是透過呼叫 AddObject 方法加入至物件內容。 | |
Deleted | 已經使用 DeleteObject 方法,從物件內容中刪除此物件。 | |
Modified | 此物件已變更,但是尚未呼叫 SaveChanges 方法。 |
以上資料部分擷轉自MSDN
EntityKey
簡單說【EntityKey】內會儲存幾個很重要的值
- EntitySet Table名稱
- EntityKeyValues 此筆資料的主鍵值
- EntityContainerName 實體容器的名稱
因為有Table名稱又有此筆資料的主鍵值,因此一個【EntityKey】就可以定義一筆資料,
ADO.Net EntityFramework去資料庫進行刪除、更新等操作時,會依靠【EntityKey】來辦別是哪一筆資料
EntityState
另一個重要的屬性是【EntityState】,會用來記錄此筆資料目前的狀態
下面利用圖示,希望讓大家了解【EntityState】內容的變化,
圖式中方框內的Detached、Add、Unchanged等,代表的是該EntityObject的EntityState內容
當下達SaveChanges方法時,ObjectContext會依照EntityStatus的值,來判斷此筆資料是要被新增、刪除、修改等。
物件間傳遞 Attech、Detech
上面介紹了兩個重要的屬性,接下來再繼續介紹ObjectContext兩個重要的Method【Attech】、【Detech】,
用在兩個ObjectContext間的Entity Object傳遞,
當Entity Object要由ObjectContext A 傳到ObjectContext B時,
必須先將其以Detach函式把與ObjectContext A的連線切斷,
在以Attach函式與ObjectContext B建立關係,
換句話說,如果在ObjectContext A取得資料,沒有透過 【Attech】、【Detech】方法,
直接到ObjectContext B中去使用的話,會發生問題
在這邊我採用漸進式的方式,來讓大家理解為什麼語法要這樣寫。
範例一
1 | User u; |
2 | using (TestEntities te = new TestEntities()) |
3 | { |
4 | 取得 某使用者 資料 |
5 | u = te.User.Where(a => a.User_name == "David" ).First(); |
6 | } |
7 |
8 | u.Group.Load(); 必須在 ObjectContext 存在下,才可以進行資料庫存取 |
這段語法執行的話,會產生以下錯誤
ObjectContext 執行個體已被處置,無法再使用於需要連接的作業。
描述: 在執行目前 Web 要求的過程中發生未處理的例外情形。請檢閱堆疊追蹤以取得錯誤的詳細資訊,以及在程式碼中產生的位置。
例外詳細資訊: System.ObjectDisposedException: ObjectContext 執行個體已被處置,無法再使用於需要連接的作業。
原因是 在執行 u.Group.Load() 時,ObjectContext已經不存在了,所以當然沒有辦法對資料庫進行存取,
此範例是讓大家知道進行資料庫存取時必須在 ObjectContext存在下執行,
當然如果只是要操作取得後的資料,沒有此限制。
那如果我真的需要在ObjectContext結束後,再繼續對資料庫進行操作的話怎辦?
例如當EntityObject在WebService間傳遞的時候就會遇到這問題,
情境如下,先取得資料,然後透過WebService傳遞到另一端,在建立一個新的ObjectContext,
將此資料利用【Attech】方法附加到ObjectContext,就可以對此資料在資料庫進行操作
範例二
01 | 範例 利用Attach、Detach在ObjectContext中傳遞 |
02 | User u; |
03 | using (TestEntities te = new TestEntities()) |
04 | { |
05 | 取得 某使用者 資料 |
06 | u = te.User.Where(a => a.User_name == "David" ).First(); |
07 | |
08 | 從物件內容中斷物件的連結 |
09 | te.Detach(u); |
10 | } |
11 |
12 | 為了示範方便,請將此想像模擬成另一個執行環境 |
13 | using (TestEntities te2 = new TestEntities()) |
14 | { |
15 | 附加相關的物件 |
16 | te2.Attach(u); |
17 | |
18 | u.Group.Load(); |
19 | var groups = u.Group.Select(a => a).ToList(); |
20 | } |
這段語法就可以順利執行,
利用圖示來觀察一下其中EntityState變化,
其中重點在利用【Attech】、【Detech】方法,讓 EntityObject可以在ObjectContext中傳遞,
也順便介紹了一下【EntityKey】、【EntityState】這兩個重要的屬性,
如果要學好ADO.Net Entity Framework並活用,這篇介紹的範圍一定要理解。
转:http://www.dotblogs.com.tw/asdtey/archive/2009/10/13/11037.aspx