ADO.Net Entity Framework : (十五) 深入探討,物件間傳遞,以及EntityKey、EntityState

在這邊分享跟介紹,使用ADO.Net Entity Framework時,一定會碰到的問題,
如何在ObjectContext間傳遞EntityObject並進行資料庫操作,
適用的情境像是在WebService、多層式架構、利用ObjectDataSource存取資料時等等,
以及【EntityKey】、【EntityState】的介紹

在這邊分享跟介紹,使用ADO.Net Entity Framework時,一定會碰到的問題,
如何在ObjectContext間傳遞EntityObject並進行資料庫操作,
簡單說就是當你從一個ObjectContext取得一筆資料(EntityObject)後,
跨越另一個類別(Class)要再利用ObjectContext去操作剛剛取得的EntityObject,
例如要新增、修改、刪除、查詢等,要如何實做,
適用的情境像是在WebService、多層式架構、利用ObjectDataSource存取資料時等等,
都會遇到此問題。
 

在實作範例之前,有幾個重要觀念與名詞必須先介紹一下
不知道大家在使用ADO.Net Entity Framework取得一筆資料的時候,
有沒有發現除了欄位名稱轉換成屬性,還自動產生了多了兩個很重要的屬性【EntityKey】、【EntityState】,
因為EntityObject實作了IEntityWithChangeTracker介面,讓這些物件能夠報告變更,
2009-10-12_170318

簡單說明一下這些屬性

名稱

說明

EntityKey

EntitySet=User;User_id=3
(此為範例)

提供實體 (Entity) 類型執行個體 (Instance) 之物件的持久參考。

EntityKey.
EntityContainerName

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內容

 2009-10-13_004035 
2009-10-13_004045
當下達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中去使用的話,會發生問題

在這邊我採用漸進式的方式,來讓大家理解為什麼語法要這樣寫。

範例一


        User u;        
        using (TestEntities te = new TestEntities())
        {
            ////取得 某使用者 資料
            u = te.User.Where(a => a.User_name == "David").First();                       
        }

        u.Group.Load();  ////必須在 ObjectContext 存在下,才可以進行資料庫存取

 這段語法執行的話,會產生以下錯誤
 

ObjectContext 執行個體已被處置,無法再使用於需要連接的作業。

描述: 在執行目前 Web 要求的過程中發生未處理的例外情形。請檢閱堆疊追蹤以取得錯誤的詳細資訊,以及在程式碼中產生的位置。
例外詳細資訊: System.ObjectDisposedException: ObjectContext 執行個體已被處置,無法再使用於需要連接的作業。


原因是 在執行 u.Group.Load() 時,ObjectContext已經不存在了,所以當然沒有辦法對資料庫進行存取,
此範例是讓大家知道進行資料庫存取時必須在 ObjectContext存在下執行,
當然如果只是要操作取得後的資料,沒有此限制。

那如果我真的需要在ObjectContext結束後,再繼續對資料庫進行操作的話怎辦?
例如當EntityObject在WebService間傳遞的時候就會遇到這問題,
情境如下,先取得資料,然後透過WebService傳遞到另一端,在建立一個新的ObjectContext,
將此資料利用【Attech】方法附加到ObjectContext,就可以對此資料在資料庫進行操作

範例二


        ////範例 利用Attach、Detach在ObjectContext中傳遞
        User u;       
        using (TestEntities te = new TestEntities())
        {
            ////取得 某使用者 資料
            u = te.User.Where(a => a.User_name == "David").First();
           
            ////從物件內容中斷物件的連結
            te.Detach(u);            
        }

        ////為了示範方便,請將此想像模擬成另一個執行環境
        using (TestEntities te2 = new TestEntities())
        {
            ////附加相關的物件
            te2.Attach(u);
           
            u.Group.Load();
            var groups = u.Group.Select(a => a).ToList();
        }

這段語法就可以順利執行,
利用圖示來觀察一下其中EntityState變化,

2009-10-13_132148

 
其中重點在利用【Attech】、【Detech】方法,讓 EntityObject可以在ObjectContext中傳遞,
也順便介紹了一下【EntityKey】、【EntityState】這兩個重要的屬性,
如果要學好ADO.Net Entity Framework並活用,這篇介紹的範圍一定要理解。
 

 下一次將介紹   【如何對中斷物件執行變更】以及【如何對附加物件執行變更】


參考資料
HOW TO:附加相關的物件 (Entity Framework)
EntityObject 類別
ObjectContext 類別
EntityKey 類別
IEntityChangeTracker 介面
IEntityChangeTracker..::.EntityState 屬性




 


 

  • 如果您覺得這篇文章有幫助,請您幫忙推薦一下或按上方的""給予支持,非常感激
  • 歡迎轉載,但請註明出處
  • 文章內容多是自己找資料學習到的心得,如有不詳盡或錯誤的地方,請多多指教,謝謝