The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

Entity Framework 學習心得分享 ( 以 LINQ to SQL 為基礎 )

剛花了些時間靜下心來讀了些 Entity Framework 相關資料,終於對 Entity Framework 有了些清楚的輪廓,由於我之前 LINQ to SQL 還算有點瞭解,對 ORM ( Object-relational mapping ) 也還算有點概念,所以在這樣的基礎之下,我相信要上手 Entity Framework 應該不是什麼難事。

我之前在從未看過任何一篇 Entity Framework 文章的情況下 ( 只看過一些入門教學影片 ),自己嘗試著試寫 Entity Framework 專案,說實在的還真的蠻挫折的,今天我就分享 4 個我所遭遇到的挫折與解決方法:

1. 使用 LINQ to Entity 預設不會自動載入關連實體(Entity)的資料

如下圖示,左圖是我在 ASP.NET MVC 中的Controller Action,右圖是 MVC 的 View,這段 Code 是無法執行的,因為 Entity Framework 並未自動載入 item.Category 的值,所以 item.Category.Title 將會引發例外事件。

return View(db.News);<%= Html.Encode(item.Category.Title) %>

而我最後研究出來的載入方法有兩種:

  1. 在 Action 裡取得 News 資料時就載入 Category 資料(如下左圖)
    return View(db.News.Include("Category"));
  2. 在 View 中執行關連資料載入的語法(如下右圖)
    item.CategoryReference.Load();

return View(db.News.Include("Category")); <% item.CategoryReference.Load(); %>

我也有將 SQL Server Profiler 打開,也發現第 1 種比較有效率,因為只要一個 SQL 查詢就可以取得所有 Entity 所需的資料。而第 2 種方法則是在每一個 foreach loop 都會向資料庫查詢資料一遍,AP 與 DB 之間的 round trip 就會非常多,當資料量大時效能就會變差。

2. 更新關連欄位的資料也頻頻失敗

以更新關連資料為例,我有兩個彼此相關的表格,分別為 Category ( 新聞類別 ) 與 News ( 新聞資料 ),News 表格中有個 CategoryID 欄位,但因為 Entity Framework 的關係,你只有 Category 這個屬性可以存取,所以你就無法直接更新 CategoryID 這個欄位的值,反而要先取出 Category 的資料,再指定給要更新的那筆 News 紀錄。我當時的寫法如下:

News n = db.News.First(p => p.ID.Equals(id));   
n.Category = db.Category.First(p => p.ID == new Guid(Request.Form["CategoryID"]));  

很不幸的,這段 Code 執行時會引發以下錯誤:

Only parameterless constructors and initializers are supported in LINQ to Entities.

而實際上正確的寫法如下:

News n = db.News.First(p => p.ID.Equals(id));
Guid cid = new Guid(Request.Form["CategoryID"]);
n.Category = db.Category.First(p => p.ID.Equals(cid));

3. 當使用 uniqueidentifier 當主索引鍵時在建立資料時需明確指定

這也不算是問題,只是當我資料庫中使用 uniqueidentifier 當主索引鍵時,在建立資料時就必須一定要指定明確的欄位植給他,否則就算在資料庫中有設定 newid() 當預設值,Entity Framework 在執行 SaveChanges() 時還是會以 00000000-0000-0000-0000-000000000000 進行新增動作。

不過若使用 int 當主索引鍵時,並設定 Identity Specification 為 Yes 的,在新增資料時就可以將設定 id 欄位的程式碼省略。

很可惜 Entity Framework 不像 LINQ to SQL 有 OnCreated 部分方法(Partial Method),可以在 OnCreated 方法中指定 Entity 的 ID 值,否則應該有些重複的程式碼可以寫在這個事件裡。

4. 在 Entity Framework 中找不到 OnValidate 方法,不知如何驗證商業邏輯規則(Business Logic)

以往在 LINQ to SQL 中,每一個 Entity 內都可以實做一些 partial method,例如 OnCreated, OnValidate 方法,其中 OnValidate 我就覺得很好用 ( 善用 LINQ to SQL 中的 partial class 機制進行資料格式驗證 ),只是在 Entity Framework 不叫做 OnValidate 方法,而且定義的位置也不在 Entity 裡,而是改在 ObjectContext 裡先實做 OnContextCreated 方法(partial method),然後在該事件裡再定義一個 SavingChanges 事件委派,然後在到委派的方法中進行商業邏輯驗證,詳細的說明可參考這篇文章:HOW TO:在儲存變更時執行商務邏輯 (Entity Framework)

---

學習新技術時,常常就是會因為卡在這一些小地方,有時後就足以讓嚐鮮者卻步,或是對新技術做出不正確的評價。

相關連結