問題html
你想使用超過一層的TPH繼承映射爲一張表建模。app
解決方案框架
假設你有一張員工(Employee)表,它包含各類類型的員工,好比,鐘點工,僱員。如圖6-10所示。ide
圖6-10 包含各類類型的員工表學習
Employee表包含鐘點工,僱員,提成員工,這是僱員下面的一個子類型。按下面的步驟,使用派生類型HourlyEmployee,SalariedEmployee和SalariedEmployee的子類CommissionedEmployee爲這張表建模。ui
一、在你的項目中建立一個繼承自DbContext的上下文對象Recipe8Context;url
二、建立POCO實體類 Employee、HourlyEmployee、SalariedEmployee和CommissionedEmployee,如代碼清單6-23所示;spa
代碼清單6-23.POCO實體類mployee, HourlyEmployee, SalariedEmployee和CommissionedEmployee翻譯
1 public abstract class Employee 2 { 3 public int EmployeeId { get; set; } 4 public string Name { get; set; } 5 } 6 7 public class SalariedEmployee : Employee 8 { 9 public decimal? Salary { get; set; } 10 } 11 12 public class CommissionedEmployee : SalariedEmployee 13 { 14 public decimal? Commission { get; set; } 15 } 16 17 public class HourlyEmployee : Employee 18 { 19 public decimal? Rate { get; set; } 20 public decimal? Hours { get; set; } 21 } 22 }
三、在上下文對象中添加一個類型爲DbSet<Employee>的屬性;code
四、在上下文對象中重寫OnModelCreating方法,配置TPH中每一個派生類的鑑別值,如代碼清單6-24所示;
代碼清單6-24. 重寫OnModelCreating方法,配置TPH中每一個派生類的鑑別值
1 protected override void OnModelCreating(DbModelBuilder modelBuilder) 2 { 3 base.OnModelCreating(modelBuilder); 4 5 modelBuilder.Entity<Employee>() 6 .HasKey(e => e.EmployeeId) 7 .Property(e => e.EmployeeId) 8 .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 9 10 modelBuilder.Entity<Employee>() 11 .Map<HourlyEmployee>(m => m.Requires("EmployeeType").HasValue("hourly")) 12 .Map<SalariedEmployee>(m => m.Requires("EmployeeType").HasValue("salaried")) 13 .Map<CommissionedEmployee>(m => m.Requires("EmployeeType").HasValue("commissioned")) 14 .ToTable("Employee", "Chapter6"); 15 }
原理
TPH繼承映射是一種靈活的建模技術。繼承樹的深度和廣度能夠進行合理地擴展,映射也容易實現。這種方法有效率,是由於它沒有引入額外的表,不涉及join鏈接。
使用Code-First來實現TPH簡單明瞭,由於面向對象的繼承,層次天然。
代碼清單6-25演示了從模型中插入和獲取。
代碼清單6-25.插入並獲取Employee的派生類型
1 using (var context = new Recipe8Context()) 2 { 3 var hourly = new HourlyEmployee 4 { 5 Name = "Will Smith", 6 Hours = (decimal)39, 7 Rate = 7.75M 8 }; 9 var salaried = new SalariedEmployee 10 { 11 Name = "JoAnn Woodland", 12 Salary = 65400M 13 }; 14 var commissioned = new CommissionedEmployee 15 { 16 Name = "Joel Clark", 17 Salary = 32500M, 18 Commission = 20M 19 }; 20 context.Employees.Add(hourly); 21 context.Employees.Add(salaried); 22 context.Employees.Add(commissioned); 23 context.SaveChanges(); 24 } 25 26 using (var context = new Recipe8Context()) 27 { 28 Console.WriteLine("All Employees"); 29 Console.WriteLine("============="); 30 foreach (var emp in context.Employees) 31 { 32 if (emp is HourlyEmployee) 33 Console.WriteLine("{0} Hours = {1}, Rate = {2}/hour", 34 emp.Name, 35 ((HourlyEmployee)emp).Hours.Value.ToString(), 36 ((HourlyEmployee)emp).Rate.Value.ToString("C")); 37 else if (emp is CommissionedEmployee) 38 Console.WriteLine("{0} Salary = {1}, Commission = {2}%", 39 emp.Name, 40 ((CommissionedEmployee)emp).Salary.Value.ToString("C"), 41 ((CommissionedEmployee)emp).Commission.ToString()); 42 else if (emp is SalariedEmployee) 43 Console.WriteLine("{0} Salary = {1}", emp.Name, 44 ((SalariedEmployee)emp).Salary.Value.ToString("C")); 45 } 46 }
代碼清單6-25的輸出以下:
All Employees ============= Will Smith Hours = 39.00, Rate = $7.75/hour JoAnn Woodland Salary = $65,400.00 Joel Clark Salary = $32,500.00, Commission = 20.00%
問題
你想在TPT繼承映射中應用條件。
解決方案
假設你有兩張如圖6-11所示的表。Toy(玩具)表描述一個公司的玩具產品,大部份手工製做的玩具用於銷售,一部分捐獻給慈善機構。在製做過程當中,有些玩具可能會損壞。損壞的玩具將被翻新。一個質檢員決定翻新玩具最終的質量。
圖6-11 玩具(Toy)表和翻新玩具(Refurbished)表間的一對一的關係
爲這家公司生成報表的應用,不須要訪問用於捐獻的玩具。按下面的步驟,使用TPT繼承映射爲Toy和RefurbishedToy表建模,同時過濾掉用於捐獻的手工玩具:
一、在你的項目中添加一個ADO.NET Entity Data Model(ADO.NET實體數據模型),並導入表Toy和ReferbishedToy;
二、刪除實體Toy與RefurbishedToy之間的關聯;
三、右鍵Toy實體,選擇Add(增長) ➤Inheritance(繼承)。選擇Toy做爲基類,RefurbishedToy做爲派生類;
四、從實體RefurbishedToy中刪除屬性ToyId;
五、選擇實體RefurbishedToy,並查看Mapping Details window(映射詳細信息窗口),將ToyId列映射到ToyId屬性。這個值未來至基類Toy;
六、從Toy實體中刪除標量屬性ForDonatinOnly;
七、選擇實體Toy,並查看Mapping Details window(映射詳細信息窗口),使用Add a Talbe or View(添加表或視圖)來映射Toy實體到實體表。添加一個條件當ForDonationOnly=0;
最終的模型如圖6-12所示。
圖6-12 Toy實體和它的派生類型RefurbishedToy實體的概念模型
原理
經過在基類中應用一個條件,咱們限制RefurbishedToy實例爲非捐獻玩具。這種方法在以下的狀況下很是有用,用一張單獨的表來實現繼承類型映射,同時使用一個固定的條件來過濾這個繼承結構。
代碼清單6-26 演示了從這個模型中插入和獲取數據。
代碼清單6-26. 從模型中插入和獲取數據
1 using (var context = new Recipe9Context()) 2 { 3 context.Database.ExecuteSqlCommand(@"insert into chapter6.toy 4 (Name,ForDonationOnly) values ('RagDoll',1)"); 5 var toy = new Toy { Name = "Fuzzy Bear", Price = 9.97M }; 6 var refurb = new RefurbishedToy 7 { 8 Name = "Derby Car", 9 Price = 19.99M, 10 Quality = "Ok to sell" 11 }; 12 context.Toys.Add(toy); 13 context.Toys.Add(refurb); 14 context.SaveChanges(); 15 } 16 17 using (var context = new Recipe9Context()) 18 { 19 Console.WriteLine("All Toys"); 20 Console.WriteLine("========"); 21 foreach (var toy in context.Toys) 22 { 23 Console.WriteLine("{0}", toy.Name); 24 } 25 Console.WriteLine("\nRefurbished Toys"); 26 foreach (var toy in context.Toys.OfType<RefurbishedToy>()) 27 { 28 Console.WriteLine("{0}, Price = {1}, Quality = {2}", toy.Name, 29 toy.Price, ((RefurbishedToy)toy).Quality); 30 } 31 }
代碼清單6-26的輸出以下:
All Toys ======== Fuzzy Bear Derby Car Refurbished Toys Derby Car, Price = 19.99, Quality = Ok to sell
實體框架交流QQ羣: 458326058,歡迎有興趣的朋友加入一塊兒交流
謝謝你們的持續關注,個人博客地址:http://www.cnblogs.com/VolcanoCloud/