問題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/