第二章 實體數據建模基礎
很有可能,你才開始探索實體框架,你可能會問“我們怎么開始?”,如果你真是這樣的話,那么本章就是一個很好的開始。如果不是,你已經建模,並在實體分裂和繼承方面感覺良好,那么你可以跳過本章。
本章將帶你漫游使用實體框架建模的基本實例,建模是實體框架的核心特性,同時也是區別實體框架和微軟早期的數據訪問平台的特性。一旦建好模,你就可以面向模型編寫代碼,而不用面向關系數據庫中的行和列。
本章以創建一個簡單概念模型的實例開始,然后讓實體框架創建底層的數據庫,剩下的實例,將向你展示,如何通過數據庫中已存在的表以及它們之間的關系來建模。
2-1 創建一個簡單模型
問題
你有一個嶄新的項目,需要創建一個模型。
解決方案
我們設想你需要創建一個管理,人員姓名、電話號碼的應用程序。為了保持盡可能的簡單,我們假設你只需要一個實體類型:Person。
按以下步驟來創建模型:
1.右鍵你的項目,然后選擇➤New Item(新建項)。
2.從模板中選擇 ADO.NET Entity Data Model(ADO.NET實體數據模型),然后點擊Add(增加)。該模板在Visual C#條目下面的Data項下面。(如圖2-1)。
圖2-1 增加一個新的.emdx文件,其中包含使用XML描述的概念模型、存儲模型、映射層
3.在向導第一步選擇Empty Model(空模型)並點擊Finish(完成)按鈕。向導將創建一個新的設計器界面上為空的概念模型。
4.右鍵設計器界面,選擇增加➤Entity(實體)。
5.在Entity Name(實體名稱)字段鍵入Person,選中Create a Key Propety(創建實體鍵)復選框,使用Id作為實體鍵並確保其類型為Int32.點擊OK按鈕,一個新的Person實體便出現在設計器窗口中(如圖2-2)。
圖2-2在概念模型中添加一個代表Person的實體類
6.右鍵Person實體頂部,然后選擇Add(添加) ➤Scalar Property(標量屬性)。一個新的標量屬性便添加到了Person實體中。
7.將增加的標量屬性重命名為Firstname.然后繼續添加標量屬性LastName、MiddleName和PhoneNumber.
8.右鍵Id屬性並選擇Properties(屬性),在屬性窗口中,如果StoreGneneratedPattern屬性值未設置為Identity時,將其設置為Identity。該標識是指Id屬性的值將由存儲層(數據庫)計算產生。最終得到的數據庫腳本會標識Id列為identity列,存儲邏輯模型也會知道,數據庫將會自動管理該列的值。
完成后的概念模型如圖2-3所示。
圖2-3 模型包含一個代表Person的實體類型
你已經完成了一個簡單的概念模型。不過從該模型生成數據庫,還有一些工作要做:
9.需要更改我們模型的一些屬性,以幫助我們生成數據庫。右鍵計設器窗口,選擇properties(屬性)。更改數據庫架構名稱(Database Schema name)為Chapter2,更改實體容器名稱(Entity Container Name)為EF6RecipesContext。如圖2-4所示。
圖2-4 更改模型屬性
10.右鍵設計器窗口並選擇Generate Database Script from Model(根據模型生成數據庫)。選擇一個已存在的數據庫連接或者新建一個連接。圖2-5,我們選擇創建一個新的本地數據庫EF6Recipes的連接。
圖2-5創建一個實體框架從概念模型創建數據庫腳本要使用的數據庫連接
11.單擊OK按鈕完成連接屬性設置,然后單擊Next(下一步)預覽數據庫腳本(如圖2-6)。一旦點擊Finish(完成),生成的腳本就被添加到你的項目中。
圖2-6 在.edmx文件中生成存儲邏輯模型並創建數據庫腳本
12.在SSMS(SQL Server Management Studio)查詢窗口中執行上面生成的數據庫腳本創建數據庫和People表。
原理
實體框架設計器是一個創建概念模型、存儲模型和映射層的強有力工具。它提供雙向建模的功能,你可以從一個空白的模型設計窗口建模,也可通過導入一個已存在的數據庫來創建概念模型、存儲模型和映射層。當前版本提供了有限的雙向建模功能,它允許從模型重新創建數據庫,根據數據庫的改變來更新模型。
概念模型擁有很多影響生成存儲邏輯模型和數據庫腳本的屬性,我們更改了其中的兩個屬性,第一個是容器的名稱,他是繼承至DbContext上下文對象。我們給它命名為EF6RecipesContext,它與本書使用的上下文對象保持一致。
另一個是,更改了表示生成存儲邏輯模型和數據庫腳本的架構名稱為“Chaper2”。
代碼清單2-1演示了,我們創建和插入Person實體類型的實例,並將所有Person實體保存到數據庫。
代碼清單2-1. 從模型中插入和獲取數據
1 using (var context = new EF6RecipesContext()) { 2 var person = new Person { 3 FirstName = "Robert", 4 MiddleName = "Allen", 5 LastName = "Doe", 6 PhoneNumber = "867-5309" 7 }; 8 context.People.Add(person); 9 person = new Person { 10 FirstName = "John", 11 MiddleName = "K.", 12 LastName = "Smith", 13 PhoneNumber = "824-3031" 14 }; 15 context.People.Add(person); 16 person = new Person { 17 FirstName = "Billy", 18 MiddleName = "Albert", 19 LastName = "Minor", 20 PhoneNumber = "907-2212" 21 }; 22 context.People.Add(person); 23 person = new Person { 24 FirstName = "Kathy", 25 MiddleName = "Anne", 26 LastName = "Ryan", 27 PhoneNumber = "722-0038" 28 }; 29 context.People.Add(person); 30 context.SaveChanges(); 31 } 32 using (var context = new EF6RecipesContext()) { 33 foreach (var person in context.People) { 34 System.Console.WriteLine("{0} {1} {2}, Phone: {3}", 35 person.FirstName, person.MiddleName, 36 person.LastName, person.PhoneNumber); 37 } 38 }
代碼清單2-1的輸出為:
John K. Smith, Phone: 824-3031
Robert Allen Doe, Phone: 867-5309
Kathy Anne Ryan, Phone: 722-0038
Billy Albert Minor, Phone: 907-2212
最佳實踐
當創建一個上下文實例時,我們使用using()語句:
using (var context = new EF6RecipesContext())
{
...
}
如果你不熟悉這種模式,也沒關系,因為它很簡單。一般情況下,我們通過new操作符並將結果賦值給變量來得到一個對象的實例,當這個變量超出其生命周期,該對象不再被別的任何對象引用。垃圾回收器會在某一個時間點開始釋放該對象所占的內存工作。 對於我們.NET應用程序中的大多數對象來說,這是一個巨大的工作,因為他們會一直占用着資源,直到垃圾回收器開始工作。而垃圾回收器具有不確定性,因為他總是按自己的計划來完成其工作,對此我能施加的影響很有限。
DbContext上下文對象的實例占用着像數據庫連接這樣的,我們希望不使用時就立即釋放的系統資源。我們真的不希望數據庫連接的釋放工作要等到垃圾回收器來完成。
using()語句有很好的特性。首先,當代碼執行完using(){}代碼塊時,上下文中的Dispose()方法會被自動調用。因為DbContext上下文實現了IDisposable接口,該方法將關閉所有數據庫連接,清理任何需要被釋放的資源。
其次,不管怎樣,只要代碼離開using(){}代碼塊,方法Dispose()就會被調用。最重要的是,代碼塊里即使遇到return語句或者是拋出了異常,它都能保證資源得到合理的釋放。
這里的最佳實踐是,當創建DbContext上下文對象時總是使用using(){}代碼塊,它將進一步幫助你創建健壯的代碼。
本篇就到這里吧,如果有翻譯不當的地方,懇請指正。如果你覺得本系值得與更多人分享,那么請點擊右下角的推薦。謝謝。本文由VolcanoCloud翻譯,轉載請注明出處。謝謝!
實體框架交流QQ群: 458326058,歡迎有興趣的朋友加入一起交流
謝謝大家的持續關注,我的博客地址:http://www.cnblogs.com/VolcanoCloud/