《Entity Framework 6 Recipes》中文翻譯系列 (10) -----第二章 實體數據建模基礎之兩實體間Is-a和Has-a關系建模、嵌入值映射


翻譯的初衷以及為什么選擇《Entity Framework 6 Recipes》來學習,請看本系列開篇

2-11 兩實體間Is-a和Has-a關系建模

問題

  你有兩張有Is-a和Has-a關系的表,你想將他們建模成兩實體間的Is-a和Has-a關系。

 

解決方案

  假設你在數據庫中,有兩張描述風景名勝公園和公園地址的表,Loacation和Part。在應用中,park是location的簡單(simply)類型(譯注:從上下文看應該是指子類)。另外,一個park有一個擁有郵寄地址的管理辦公室,這個地址同樣也可以用表location來表示。那么,一個park實體既是Location的派生類,又有一個與管理辦公室相對應的地址。辦公室完全有可能不位於公園內,也許幾個公園的管理辦公室都在附近的同一個小鎮上。圖2-21顯示表Park和Location的數據庫關系圖。

圖2-21 表Location和Park的Has-a和Is-a關系

 

  按下面的步驟,為這兩個關系建模:

    1、右鍵你的項目,選擇Add(增加) ➤New Item(新建項),然后選擇Visual C#條目下的Data模板下的ADO.NET Entity Data Model(ADO.NET實體數據模型)。

    2、選擇Generate from database 從一個已存在的數據庫創建模型,點擊Next(下一步)。

    3、可以選擇一個已存在的數據庫連接,也可以選擇新建一個數據庫連接。

    4、在選擇數據庫窗口,選擇表Location和Park。后勾選上確定所生成對象名稱的單復數形式、在模型中包含外鍵列復選框。點擊Finish(完成)

    5、刪除實體數據模型向導生成的關聯1-to-0或者1;

    6、右鍵Location實體,選擇 Add(增加) ➤Inheritance(繼承)。選擇實體Park作為派生類實體,Location作為基類實體;

    7、從Park實體類型刪除屬性ParkId;

    8、單擊Part實體並查看映射詳細信息窗口,如果映射詳細信息窗口未顯示。選擇工具菜單View(視圖) ➤Other Windows(其它窗口) ➤Entity Data Model Mapping Details(實體數據模型映射詳細信息)。在映射詳細信息窗口中將ParkId列映射到LocationId屬性;

    9、修改Park實體類型的導航屬性名為Office,它代表park的辦公位置。

    完成后的模型如圖2-22所示。

圖2-22 Park繼承自Loacation,一個Park is-a location,一個Park has-a 它的辦公location

 

原理

  在這個示例中,實體間超過一個關聯。我們使用TPT繼承映射創建了一個Is-a關系,實體Loaction為基類,實體Park為派生類。我們同時使用一個1對多關聯在Locaton和Park實體間創建一個Has-a關系。

  在代碼清單2-26中,我們演示了創建一個Park實體實例,因為Is-a關系,等同我們也創建了一個Loacation實例。 我們把管理辦公室地址附加給Park,這樣會導致在Location表中插入第二行。

 代碼清單2-26 創建和獲取Park和Location實體

 

 1 using (var context = new EF6RecipesContext()) {
 2                 var park = new Park {
 3                     Name = "11th Street Park",
 4                     Address = "801 11th Street",
 5                     City = "Aledo",
 6                     State = "TX",
 7                     ZIPCode = "76106"
 8                 };
 9                 var loc = new Location {
10                     Address = "501 Main",
11                     City = "Weatherford",
12                     State = "TX",
13                     ZIPCode = "76201"
14                 };
15                 park.Office = loc;
16                 context.Locations.Add(park);
17                 park = new Park {
18                     Name = "Overland Park",
19                     Address = "101 High Drive",
20                     City = "Springtown",
21                     State = "TX",
22                     ZIPCode = "76081"
23                 };
24                 loc = new Location {
25                     Address = "8705 Range Lane",
26                     City = "Springtown",
27                     State = "TX",
28                     ZIPCode = "76081"
29                 };
30                 park.Office = loc;
31                 context.Locations.Add(park);
32                 context.SaveChanges();
33             }
34 
35 
36             using (var context = new EF6RecipesContext()) {
37                 context.ContextOptions.LazyLoadingEnabled = true;
38                 Console.WriteLine("-- All Locations -- ");
39                 foreach (var l in context.Locations) {
40                     Console.WriteLine("{0}, {1}, {2} {3}", l.Address, l.City,
41                     l.State, l.ZIPCode);
42                 }
43                 Console.WriteLine("--- Parks ---");
44                 foreach (var p in context.Locations.OfType<Park>()) {
45                     Console.WriteLine("{0} is at {1} in {2}", p.Name, p.Address, p.City);
46                     Console.WriteLine("\tOffice: {0}, {1}, {2} {3}", p.Office.Address,
47                     p.Office.City, p.Office.State, p.Office.ZIPCode);
48                 }
49             }

  代碼清單2-26的輸出為:

-- All Locations --501 Main, Weatherford, TX 76201
801 11th Street, Aledo, TX 76106
8705 Range Lane, Springtown, TX 76081
101 High Drive, Springtown, TX 76081
--- Parks ---11th Street Park is at 801 11th Street in Aledo
Office: 501 Main, Weatherford, TX 76201
Overland Park is at 101 High Drive in Springtown
Office: 8705 Range Lane, Springtown, TX 76081

  

2-12 創建、修改和映射復合類型

問題

  你想創建一個復合類型,將它設置實體的一個屬性,然后映射該屬性到數據庫表中的多列。 (譯注:這就是領域模型中的嵌入值映射,這對喜歡DDD的人來說,這小節和前面的TPT,TPH都應該掌握

 

解決方案

  假設你在數據庫中有圖2-23所示的表,你想為FirtstName和LastName列創建一個復合類型的屬性Name. 為AddressLine1、AddressLine2、City、State以及ZIPCode列創建一個復合類型屬性Address。這些復合類型在模型中都是實體中的屬性,如圖2-24所示。

 

圖2-23 Agent實體和他的復合屬性name和address

圖2-24 表Agent

   按下面的步驟,為Name和Address復合類型建模:

    1、右鍵你的項目,選擇Add(增加) ➤New Item(新建項),然后選擇Visual C#條目下的Data模板下的ADO.NET Entity Data Model(ADO.NET實體數據模型)。

    2、選擇Generate from database 從一個已存在的數據庫創建模型,點擊Next(下一步)。

    3、可以選擇一個已存在的數據庫連接,也可以選擇新建一個數據庫連接。

    4、在選擇數據庫窗口,選擇表Agent。后勾選上確定所生成對象名稱的單復數形式、在模型中包含外鍵列復選框。點擊Finish(完成);

    5、選擇FirstName和LastName屬性,右鍵,選擇Refactor(重構)➤ Into Complex Type(移動到新的復合類型);

    6、在模型瀏覽器中,將這個新的復合類型ComplexType1重命名為Name,這將改變這個類型的名字。在實體Agent上,重命名屬性ComplexTypePeroperty為Name,這將改變屬性的名稱。

    7、為了演示另一種方法,我們從頭開始創建下一個復合類型,在設計窗口中右鍵,選擇Add(增加)➤Complex Type(復合類型);

    8、在模型瀏覽器中,重命名這個新創建的復合類型ComplexType1的名稱為Address;

    9、在實體Agent中選擇屬性AddressLine1、AddressLine2、City、State以及ZipCode,右鍵選擇Cut(剪切),在模型瀏覽器中將這些屬性粘貼到復合類型Address;

    10、右鍵實體Agent,選擇Add(添加) ➤Complex Property(復合類型)。將其重命名為Address;

    11、右鍵新創建的Address屬性,選擇Properties(屬性),改變其類型為Address。這將改變新創建的屬性的類型為Address復合類型;

    12、在映射詳細信息窗口,查看Agnet映射信息。將表Agent中的列映射到我們剛創建的兩個復合類型上,如圖2-25所示。

 

圖2-25 映射復合類型字段到Agent表

 

原理

  復合類型允許你將一組屬性包含到一個用於實體屬性的單獨類型,一個復合類型可以包含標量屬性和其它的復合類型,但不能包含導航屬性和實體集合。一個復合類型不能是一個實體鍵。復合類型不能在上下文對象中被跟蹤。

  類型為復合類型的屬性不能為null,當你使用包含復合類型屬性的實體時,你必須記住這條准則。偶爾,當復合類型屬性的值在特定的操作中不重要時,我可以為其創建一個虛值(dummy value),使它有一個不為null的值。

  當你修改了復合類型屬性中的任一字段,這個屬性將被實體框架標記為已改變(changed),一個將更新復合類型所有字段的更新語句會被生成。

  代碼清單2-27 演示在模型中插入一些數據,然后再顯示它們

代碼清單2-27.插入Agents,然后從模型中查詢數據

 

 1  using (var context = new EF6RecipesContext()) {
 2                 var name1 = new Name { FirstName = "Robin", LastName = "Rosen" };
 3                 var name2 = new Name { FirstName = "Alex", LastName = "St. James" };
 4                 var address1 = new Address {
 5                     AddressLine1 = "510 N. Grant",
 6                     AddressLine2 = "Apt. 8",
 7                     City = "Raytown",
 8                     State = "MO",
 9                     ZIPCode = "64133"
10                 };
11                 var address2 = new Address {
12                     AddressLine1 = "222 Baker St.",
13                     AddressLine2 = "Apt.22B",
14                     City = "Raytown",
15                     State = "MO",
16                     ZIPCode = "64133"
17                 };
18 
19                 context.Agents.Add(new Agent { Name = name1, Address = address1 });
20                 context.Agents.Add(new Agent { Name = name2, Address = address2 });
21                 context.SaveChanges();
22             }
23             using (var context = new EF6RecipesContext()) {
24                 Console.WriteLine("Agents");
25                 foreach (var agent in context.Agents) {
26                     Console.WriteLine("{0} {1}", agent.Name.FirstName, agent.Name.LastName);
27                     Console.WriteLine("{0}", agent.Address.AddressLine1);
28                     Console.WriteLine("{0}", agent.Address.AddressLine2);
29                     Console.WriteLine("{0}, {1} {2}", agent.Address.City,
30                     agent.Address.State, agent.Address.ZIPCode);
31                     Console.WriteLine();
32                 }
33             }

代碼清單2-27的輸入如下:

Agents
Robin Rosen
510 N. Grant
Apt. 8
Raytown, MO 64133
Alex St. James
222 Baker St.
Apt.22B
Raytown, MO 64133


 

本篇稍微有點長,感覺你的耐心閱讀,轉載請注明出處:http://www.cnblogs.com/VolcanoCloud/p/4492614.html                

 

 

實體框架交流QQ群:  458326058,歡迎有興趣的朋友加入一起交流

謝謝大家的持續關注,我的博客地址:http://www.cnblogs.com/VolcanoCloud/

       

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM