《Entity Framework 6 Recipes》中文翻譯系列 (36) ------ 第六章 繼承與建模高級應用之TPC繼承映射

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

6-12  TPC繼承映射建模

問題html

  你有兩張或多張架構和數據相似的表,你想使用TPC繼承映射爲這些表建模。數據庫

解決方案瀏覽器

  假設咱們有如圖6-18所示的表。架構

圖6-18 表Toyota和BMW有類似的結構,它們能夠成爲派生至實體Car的派生類型app

 

  在圖6-18中,表Toyota和BMW有類似的架構(Schema),並描述相似的數據。BMW表只多了額外的一列,它用一bit值來指示對應的實例是否具備避免碰撞(collision-avoidance)特性。咱們想在建模中,用一個基類來持有表Toyta和BMW的公共屬性。另外,咱們還想表示經銷商與汽車庫存量之間的一對多關係。 圖6-22(譯註:應該是圖6-19)展現的是最終的模型。框架

  按下面的步驟建立模型:編輯器

    一、在你的項目中添加一個ADO.NET Entity Data Model(ADO.NET實體數據模型),並導入表Toyota,BMW,CarDealer和Dealer;性能

    二、右鍵設計器,並選擇Add(新增)➤Entity(實體)。命名新實體爲Car,不勾選Create Key property(建立鍵屬性)複選框;學習

    三、右鍵實體Car,選擇Properties(屬性)。設置Abstract(抽象)屬性爲True;網站

    四、將實體Toyota和BMW的公共屬性移動到實體Car中,可使用Cut/Paste(剪切/粘貼)來完成移動。確保Toyota實體沒有屬性,BMW實體只有CollisionAvoidance實體。這兩個實體將從實體Car繼承公共屬性;

    五、右鍵Car實體,選擇Add(增長) ➤Inheritance(繼承)。選擇Car做爲基類,BMW做爲派生類。

    六、重複上一步的操做,選擇Car做爲基類,Toyota做爲派生類型。

    七、右鍵CarDealer實體,選擇Delete(刪除)。當提示是否從存儲模型刪除CarDealer時,選擇No(否);

    八、右鍵設計器,選擇Add(增長) ➤Association(關聯)。命名關聯爲CarDealer。在左邊選擇Dealer,並將多重性設置爲1,在右邊選擇Car,並將多重性設置爲多。將Car這邊的導航屬性命名爲Dealer,將Dealer這邊的導航屬性命名爲Cars。確保不勾選Add foreign key properties(添加外鍵屬性);

    九、選擇關聯,而後查看Mapping Details window(映射詳細信息窗口)。在Add a Talbe or View(添加表或視圖)下面菜單中,選擇CarDealer。確保DealerId屬性映射到DealerId列,CarID屬性映射到CarId列;

  在解決方案瀏覽器中右鍵.edmx文件,選擇Open With(打開方式) ➤XML Editor(XML文本編輯器),使用代碼清單6-3中的更改成實體BMW和Toyota編輯映射節.

代碼清單6-35. 映射實體BMW和Toyota到表

 1     <EntitySetMapping Name="Cars">
 2                 <EntityTypeMapping TypeName="IsTypeOf(Apress.EF6Recipes.BeyondModelingBasics.Recipe12.BMW)">
 3                     <MappingFragment StoreEntitySet="BMW">
 4                         <ScalarProperty Name="CollisionAvoidance"
 5                                         ColumnName="CollisionAvoidance" />
 6                         <ScalarProperty Name="CarId" ColumnName="CarId"/>
 7                         <ScalarProperty Name="Model" ColumnName="Model"/>
 8                         <ScalarProperty Name="Year" ColumnName="Year"/>
 9                         <ScalarProperty Name="Color" ColumnName="Color"/>
10                     </MappingFragment>
11                 </EntityTypeMapping>
12                 <EntityTypeMapping TypeName="IsTypeOf(Apress.EF6Recipes.BeyondModelingBasics.Recipe12.Toyota)">
13                     <MappingFragment StoreEntitySet="Toyota">
14                         <ScalarProperty Name="CarId" ColumnName="CarId"/>
15                         <ScalarProperty Name="Model" ColumnName="Model"/>
16                         <ScalarProperty Name="Year" ColumnName="Year"/>
17                         <ScalarProperty Name="Color" ColumnName="Color"/>
18                     </MappingFragment>
19                 </EntityTypeMapping>
20             </EntitySetMapping>

最終的模型如圖6-19所示。

圖6-19  概念模型,它描述了派生類型BMW和Toyota在數據庫表示爲單獨的表

 

原理

  TPC是一個有趣的繼承模型,它容許每一個派生類實體映射到單獨的物理表。從實用的角度來看,表至少有一部分公共的架構。 這個公共的的架構被映射到基類,額外部分的架構映射到派生類實體。爲了讓TPC繼承模型正常工做,實體鍵在整個相關表(譯註:如本示例中的表Toyota和BMW)中必須惟一

  基類實體被標記爲抽象類型,它不被映射到任何表。在TPC中,只有派生類型實體被映射到表

  在咱們的示例中,咱們標記Car實體爲抽象類型,不對它進行映射。注意,在代碼清單6-35的映射中,咱們只映射派生類型BMW和Toyota。咱們將公共屬性(CarID,Model,Year和Color)移動到了基類實體。派生類只包含屬於本身的獨特的屬性。 實例中,BMW實體的實例有一個額外的屬性CollisionAvoidance。

  由於實體Toyota和BMW派生至實體Car,因此,它們變成了相同實體集Cars的一部分。這意味着,實體鍵必須在包含整個派生類型的實體集中惟一。由於實體被映射到不一樣的表,因此我有可能會碰到相同的鍵。爲了不這種狀況的發生,咱們將每張表的CarId列設置爲標識列。對於BMW表,咱們將主鍵的種子(基數)初始化爲1並設置遞增爲2,這將會爲主鍵CarId建立奇數值。對於Toyota表,咱們將主鍵的種子初始化爲2並設置增量爲2,這將爲主鍵CarId建立偶數值。

  當在使用TPC繼承映射建模關係時,在派生中定義關係比在基類中定義更好。這是由於實體框架在運行時不知道關聯的另外一端是哪張物理表。固然,在咱們的示例中,咱們提供了一張單獨的表(CarDealer),它包含了關係。這就容許咱們能夠在基類中映射關係到CarDealer表。

  在不少使用TPC繼承映射的實際應用,最多見的也許是,處理存檔數據。假設你的電子商務網站有多年的訂單數據。在每一年的年終,你將前面12個月的訂單存檔在Archive表,併爲新的一年準備一張空表。你可使用這裏演示的方法,用TPC爲當前和存檔的訂單建模。

  TPC繼承映射跟別的繼承映射相比,有一個特別重要的性能優點。當查詢一個一派生類型時,產生針對底層數據庫表的查詢,沒有像TPT繼承映射中額外的join鏈接,也沒有像TPH中的過濾。對於有幾個派生類型的大型數據集或模型,這種性能優點顯得相當重要。

  TPC繼承映射的缺點是,包含對潛在重複數據的開銷,和在整個相關表中確保主鍵惟一的複雜性。在存檔場景中,數據不是重複,只是簡單的分佈在多張表中。在別的場景中,數據(屬性)在相關表中可能會有重複。

  代碼清單6-36演示了從模型中插入和獲取數據。

代碼清單6-36.從模型中插入和獲取數據

 1  using (var context = new Recipe12Context())
 2             {
 3                 var d1 = new Dealer { Name = "All Cities Toyota" };
 4                 var d2 = new Dealer { Name = "Southtown Toyota" };
 5                 var d3 = new Dealer { Name = "Luxury Auto World" };
 6                 var c1 = new Toyota
 7                 {
 8                     Model = "Camry",
 9                     Color = "Green",
10                     Year = 2014,
11                     Dealer = d1
12                 };
13                 var c2 = new BMW
14                 {
15                     Model = "310i",
16                     Color = "Blue",
17                     CollisionAvoidance = true,
18                     Year = 2014,
19                     Dealer = d3
20                 };
21                 var c3 = new Toyota
22                 {
23                     Model = "Tundra",
24                     Color = "Blue",
25                     Year = 2014,
26                     Dealer = d2
27                 };
28                 context.Dealers.Add(d1);
29                 context.Dealers.Add(d2);
30                 context.Dealers.Add(d3);
31                 context.SaveChanges();
32             }
33 
34             using (var context = new Recipe12Context())
35             {
36                 Console.WriteLine("Dealers and Their Cars");
37                 Console.WriteLine("======================");
38                 foreach (var dealer in context.Dealers)
39                 {
40                     Console.WriteLine("\nDealer: {0}", dealer.Name);
41                     foreach (var car in dealer.Cars)
42                     {
43                         string make = string.Empty;
44                         if (car is Toyota)
45                             make = "Toyota";
46                         else if (car is BMW)
47                             make = "BMW";
48                         Console.WriteLine("\t{0} {1} {2} {3}", car.Year,
49                                            car.Color, make, car.Model);
50                     }
51                 }
52             }

代碼清單6-36的輸出以下:

Dealer: Luxury Auto World
    2014 Blue BMW 310i
Dealer: Southtown Toyota
    2014 Blue Toyota Tundra
Dealer: All Cities Toyota
    2014 Green Toyota Camry

 

 

 

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

謝謝你們的持續關注,個人博客地址:http://www.cnblogs.com/VolcanoCloud/

相關文章
相關標籤/搜索