《Entity Framework 6 Recipes》中文翻譯系列 (33) ------ 第六章 繼承與建模高級應用之TPH與TPT (2)

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

6-8  嵌套的TPH建模

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

 

 

6-9  在TPT繼承映射中應用條件

問題

  你想在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/

相關文章
相關標籤/搜索