不知道對EF感興趣的並不多,還是我翻譯有問題(如果是,懇請你指正),通過前幾篇的反饋,閱讀這個系列的人不多。不要這事到最后成了吃不討好的事就麻煩了,廢話就到這里,直奔主題。
2-2 從已存在的數據庫創建模型
問題
有一個存在的數據庫,它擁有表、也許還有視圖、外鍵。你想通過它來創建一個模型。
解決方案
讓我們設想,你擁有一個描述詩人(Poet)以及他們的詩(Poem),還有他們之間關系的數據庫。如圖2-7所示。
圖2-7 一個關於詩人及他們的詩的簡單數據庫
從上圖可以看出,一個詩人可能是一首或多首詩的作者,每首詩可以按其韻律來分類,韻律是詩句的基本模式。上圖未顯示數據庫中將表連接在一起的視圖,它讓我們更容易的枚舉詩人,詩和韻律。
按下列步驟,將表、視圖以及關系導入到模型:
1、右鍵你的項目,選擇Add(增加) ➤New Item(新建項)。
2、選擇Visual C#條目下的Data模板下的ADO.NET Entity Data Model(ADO.NET實體數據模型)。
3、選擇Generate from database 從一個已存在的數據庫創建模型,點擊Next(下一步)。
4、可以選擇一個已存在的數據庫連接,也可以選擇新建一個數據庫連接,如果你選擇新建,你將要選擇數據庫服務器、認證方式(Windwos or SQL Server)以及一個數據庫。你一旦選擇好,便可以點擊Test Connection(測試連接)測試連接是否可用。測試好后,點擊Next(下一步)。
彈出的對話框中顯示了數據庫所有的表、視圖以及存儲過程。選擇你希望包含在模型中的項。我們選擇所有的表(Meter,Poem,Poet),視圖(vwLibrary),然后勾選上確定所生成對象名稱的單復數形式、在模型中包含外鍵列復選框。我們將會進一步對此時行討論。圖2-8展示了我們所做的選擇。
圖2-8 選擇表、視圖包含進模型,勾選上確定所生成對象名稱的單復數形式、在模型中包含外鍵列復選框
當點擊Finish(完成),向導會生成一個包含三張表和一個視圖的模型。向導從數據庫讀取外鍵約束,並推導出Poet和Poem(s)之間的一對多關系,還有Meter和Poem(s)之間的一對多關系。
圖2-9 概念模型
圖2-9展示了一個包含表Poet,Poem以及Meter、視圖vwLibrary的模型。
現在,你擁有了一個可以在代碼中使用的模型。請注意, vwLibrary實體是基於數據中的視圖vwLibrary的。在絕大多數據庫中,視圖是只讀的,插入、刪除、更新不被支持。在實體框架中也同樣如此,實體框架把視圖視為只讀。你可以通過映射存儲過程來解決基於視圖的實體的創建、更新和刪除動作。我們將在第六章對此進行演示。
原理
讓我們一起來看導入向導為我們創建的模型。請注意,實體中已經包含了標量屬性和導航屬性。標量屬性被映射到數據庫表中列,導航屬性卻來至數據庫中的表間關系。
在數據庫關系圖中,一個poem擁有一個meter和一個poet(作者)。這符合Meter和Poet中的導航屬性。如果我有一個Poem實體的實例,導航屬性Poet將引用一個Poet實體的實例,導航屬性Meter將引用一個Meter實體的實例。
一個Poet可能是多首詩的作者,它其中的導航屬性Poems包含一個Poem實體的實例集合。這個集合可能是空的,這代表該詩人還未創建任何一首詩。對於Meter實體,其中的導航屬性Poems同樣也是一個集合。該導航屬性包含屬於指定Meter的Poem實體實例的集合。SQL Server不支持在視圖上創建關系,這在模型中反映為一個沒有導向屬性的vwLibrary實體。
導入向導在包含集合的導航屬性的名稱單復數形式上表示得相當的聰明。當你右鍵實體去查看他的Properties(屬性),你會看到每個實體的實體集的名稱同樣為復數形式。例如Poem實體的實體集名稱為Poems. 這種自動添加復數利益於,勾選上確定所生成對象名稱的單復數形式復選框。
勾選在模型中包含外鍵列復選框選項,使外鍵也包含在了模型中。雖然看上去,在擁有導航屬性的同時好像沒有必要再擁有外鍵屬性。對此,我們會在接下來的技巧中演示擁有一個可直接訪問外鍵屬性的好處。
代碼清單2-2,演示了如何在模型中創建Poet,Poem以及Meter實體的實例並將他們保存到數據為。同時也演示了,如何通過查詢模型從數據庫中獲取到poets和poems。
代碼清單2-2.在模型中插入和查詢
1 using (var context = new EF6RecipesContext()) { 2 var poet = new Poet { FirstName = "John", LastName = "Milton" }; 3 var poem = new Poem { Title = "Paradise Lost" }; 4 var meter = new Meter { MeterName = "Iambic Pentameter" }; 5 poem.Meter = meter; 6 poem.Poet = poet; 7 context.Poems.Add(poem); 8 poem = new Poem { Title = "Paradise Regained" }; 9 poem.Meter = meter; 10 poem.Poet = poet; 11 context.Poems.Add(poem); 12 poet = new Poet { FirstName = "Lewis", LastName = "Carroll" }; 13 poem = new Poem { Title = "The Hunting of the Shark" }; 14 meter = new Meter { MeterName = "Anapestic Tetrameter" }; 15 poem.Meter = meter; 16 poem.Poet = poet; 17 context.Poems.Add(poem); 18 poet = new Poet { FirstName = "Lord", LastName = "Byron" }; 19 poem = new Poem { Title = "Don Juan" }; 20 poem.Meter = meter; 21 poem.Poet = poet; 22 context.Poems.Add(poem); 23 context.SaveChanges(); 24 } 25 using (var context = new EF6RecipesContext()) { 26 var poets = context.Poets; 27 foreach (var poet in poets) { 28 Console.WriteLine("{0} {1}", poet.FirstName, poet.LastName); 29 foreach (var poem in poet.Poems) { 30 Console.WriteLine("\t{0} ({1})", poem.Title, poem.Meter.MeterName); 31 } 32 } 33 } 34 35 // 使用視圖 vwLibrary 36 using (var context = new EF6RecipesContext()) { 37 var items = context.vwLibraries; 38 foreach (var item in items) { 39 Console.WriteLine("{0} {1}", item.FirstName, item.LastName); 40 Console.WriteLine("\t{0} ({1})", item.Title, item.MeterName); 41 } 42 }
代碼清單2-2中第一個代碼塊,我們創建 了Poet,Poem以及Meter實體類型的實例,詩人John Milton,他的詩“Paradise Lost"以及該詩的韻律,該詩屬於五步抑揚格-Iambic Pentameter(詩的一種韻律)。我們一旦創建Poem實體類型的實例peom,並設置poem的Meter屬性指向meter實例,Poet屬性指向poet實例。使用相同的方法,我們創建其它的實體及關系。一旦完成創建,我們就可以調用SaveChanges()方法生成並執行適當的SQL語句,在底層數據庫中插入數據。
代碼清單2-2的輸出發下:
Lord Byron
Don Juan (Anapestic Tetrameter)
Lewis Carroll
The Hunting of the Shark (Anapestic Tetrameter)
John Milton
Paradise Regained (Iambic Pentameter)
Paradise Lost (Iambic Pentameter)
Lewis Carroll
The Hunting of the Shark (Anapestic Tetrameter)
Lord Byron
Don Juan (Anapestic Tetrameter)
John Milton
Paradise Regained (Iambic Pentameter)
John Milton
Paradise Lost (Iambic Pentameter)
在代碼中,我們最開始創建實例poet,poem以及 John Milton第一首詩的韻律meter。一旦我們創建好,就可以設置poem的導航屬性Meter為meter實例,Poet導航屬性為poet實例.實例poem的所有設置已完成,調用Add()方法將其添加到上下文中。接下來的工作將由實體框架來完成,包括添加poem到poet實例的導航屬性Poems集合中,添加poem到meter實例的導航屬性Poems集合中。使用相同的步驟完成剩下的任務。為了縮減代碼,我們復用了變量和實例。
一旦創建完所有實例,並完成導航屬性的初始化,我們就完成了一個對象圖的創建。實體框架保持創建對象圖的所有修改,這此跟蹤是在數據庫上下文中實現的。變量 context包含一個數據庫上下文的實例(它的類型是DbContext),它是我們用來跟蹤創建對象圖所做修改的對象,調用其SaveChanges()方法,可以將所有修改發送到數據庫中。
接來可以查詢模型,以驗證我們保存在數據庫的數據。我們使用了一個新的上下文對象以及使用LINQ to Entities來查詢。我們本來可以重用之前的上下文對象,但是我們知道它已經在內存中有了對象圖,接下來的查詢都不會通過數據庫就直接從內存中就獲取了(譯注:這樣就達不到驗證的目的了)。
使用LINQ to Entities,我們查詢出所有的詩人(poets),然后打印出每一位詩人的姓名,以及該詩人的每一首詩的詳細信息。代碼非常簡單,但使用了兩個嵌套的循環來實現。
最后一段代碼塊使用VwLibrary實體,該實體基於vwLibrary視圖。vwLibrary視圖把表連接在一起使其扁平化以提供一個更清晰的視角。我們通過vwLibraties實體集查詢每位詩人的相關信息時,僅需要一次循環。輸出有略有不同,因為我們在每首詩中重復了詩人的的姓名。
此示例中最后需要注意的是,我們沒有通過視圖vwLibrary插入poests,poems以及meters。因為在絕大多數的數據庫中,視圖是只讀的。我在實體框架中,我們同樣不能能過視圖實體插入(或者更新、刪除)實體。當然,我們將會在本書后面部分給你演示如何克服這個困難!
本篇就到這里吧。弄飯吃去了。 如果你覺得不錯的話,請點擊右下角的 推薦,一來是給我動力,二來是分享給更多的人。謝謝。
實體框架交流QQ群: 458326058,歡迎有興趣的朋友加入一起交流
謝謝大家的持續關注,我的博客地址:http://www.cnblogs.com/VolcanoCloud/