《Entity Framework 6 Recipes》中文翻译系列 (33) ------ 第六章 继承与建模高级应用之TPH与TPT (2)

翻译的初衷以及为什么选择《Entity Framework 6 Recipes》来学习,请看本系列开篇

6-8  嵌套的TPH建模

问题

  你想使用超过一层的TPH继承映射为一张表建模。

解决方案

  假设你有一张员工(Employee)表,它包含各种类型的员工,比如,钟点工,雇员。如图6-10所示。

图6-10 包含各种类型的员工表

  Employee表包含钟点工,雇员,提成员工,这是雇员下面的一个子类型。按下面的步骤,使用派生类型HourlyEmployee,SalariedEmployee和SalariedEmployee的子类CommissionedEmployee为这张表建模。

    1、在你的项目中创建一个继承自DbContext的上下文对象Recipe8Context;

    2、创建POCO实体类 Employee、HourlyEmployee、SalariedEmployee和CommissionedEmployee,如代码清单6-23所示;

代码清单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 }

    3、在上下文对象中添加一个类型为DbSet<Employee>的属性;

    4、在上下文对象中重写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表建模,同时过滤掉用于捐献的手工玩具:

    1、在你的项目中添加一个ADO.NET Entity Data Model(ADO.NET实体数据模型),并导入表Toy和ReferbishedToy;

    2、删除实体Toy与RefurbishedToy之间的关联;

    3、右键Toy实体,选择Add(增加) ?Inheritance(继承)。选择Toy作为基类,RefurbishedToy作为派生类;

    4、从实体RefurbishedToy中删除属性ToyId;

    5、选择实体RefurbishedToy,并查看Mapping Details window(映射详细信息窗口),将ToyId列映射到ToyId属性。这个值将来至基类Toy;

    6、从Toy实体中删除标量属性ForDonatinOnly;

    7、选择实体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/

时间: 2024-10-14 04:56:09

《Entity Framework 6 Recipes》中文翻译系列 (33) ------ 第六章 继承与建模高级应用之TPH与TPT (2)的相关文章

《Entity Framework 6 Recipes》中文翻译系列 (32) ------ 第六章 继承与建模高级应用之TPH与TPT (1)

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-6  映射派生类中的NULL条件 问题 你的表中,有一列允许为null.你想使用TPH创建一个模型,列值为null时,表示一个派生类型,不为null时,表示另一个派生类型. 解决方案 假设你有一张表,描述医学实验药物.这张表包含一列指示该药是什么时候批准生产的.药在批准生产之前都被认为是实验性的.一但批准生产,它就被认为是药物了.我们就以图6-7中Drug表开始我们这一小节的学习. 图6

《Entity Framework 6 Recipes》中文翻译系列 (35) ------ 第六章 继承与建模高级应用之TPH继承映射中使用复合条件

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-11  TPH继承映射中使用复合条件 问题 你想使用TPH为一张表建模,建模中使用的复杂条件超过了实框架能直接支持的能力. 解决方案 假设我们有一张Member表,如图6-15所示.Member表描述了我们俱乐部的会员信息.在我们的模型中,我们想使用TPH为派生类,AdultMember(成人会员).SeniorMember(老年人会员)和TeenMember(青少年会员)建模. 图6-

《Entity Framework 6 Recipes》中文翻译系列 (30) ------ 第六章 继承与建模高级应用之多对多关联

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第六章  继承与建模高级应用 现在,你应该对实体框架中基本的建模有了一定的了解,本章将帮助你解决许多常见的.复杂的建模问题,并解决你可能在现实中遇到的建模问题. 本章以多对多关系开始,这个类型的关系,无论是在现存系统还是新项目的建模中都非常普遍.接下来,我们会了解自引用关系,并探索获取嵌套对象图的各种策略.最后,本章以继承的高级建模和实体条件结束. 6-1  获取多对多关联中的链接表 问题

《Entity Framework 6 Recipes》中文翻译系列 (36) ------ 第六章 继承与建模高级应用之TPC继承映射

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-12  TPC继承映射建模 问题 你有两张或多张架构和数据类似的表,你想使用TPC继承映射为这些表建模. 解决方案 假设我们有如图6-18所示的表. 图6-18 表Toyota和BMW有相似的结构,它们可以成为派生至实体Car的派生类型 在图6-18中,表Toyota和BMW有相似的架构(Schema),并描述类似的数据.BMW表只多了额外的一列,它用一bit值来指示对应的实例是否具有避

《Entity Framework 6 Recipes》中文翻译系列 (34) ------ 第六章 继承与建模高级应用之多条件与QueryView

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-10  创建一个多条件过滤 问题 你想使用多个条件为实体过滤表中的行. 解决方案 假设你有一张处理网站订单的表,如图6-13所示. 图6-13 表WebOrder包含网站订单的信息 假设我们有这样一个业务需求,WebOrder中的实例为,2012年以后的,2010年到2012年之间未删除的,2010年以前的订单金额大于200美元的.这样的复杂过滤条件不能使用映射详细信息窗口中有限制的条件

《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-13  在基类中应用条件 问题 你想从一个已存在的模型中的实体派生一个新的实体,允许基类被实例化. 解决方案 假设你有如图6-20所示的模型. 图6-20 包含Invoice实体的模型 这个模型只包含一个单独的实体Invoice(发货单).我们想从Invoice派生一个新的实体,它表示删除掉的发货单.这将允许我们以更清晰的业务逻辑来分别对有效的发货单和已删除掉的发货进行不同的操作.按下面

《Entity Framework 6 Recipes》中文翻译系列 (31) ------ 第六章 继承与建模高级应用之自引用关联

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-4  使用TPH建模自引用关系 问题 你有一张自引用的表,它代表数据库上不同类型但关联的对象.你想使用TPH为此表建模. 解决方案 假设你有一张如图6-5所示的表,它描述了关于人的事,人通常会有一个心中英雄,他最能激发自己.我们用一个指向Person表中的另一个行的引用来表示心中的英雄. 图6-5  包含不同角色的Person表 在现实中,每个人都会有一个角色,有的是消防员,有的是教师,

《Entity Framework 6 Recipes》中文翻译系列 (16) -----第三章 查询之左连接和在TPH中通过派生类排序

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-10应用左连接 问题 你想使用左外连接来合并两个实体的属性. 解决方案 假设你有如图3-11所示的模型. 图3-11 一个包含Product和TopSelling的模型 畅销产品有一个与之关联的TopSelling实体.当然,不是所有的产品都是畅销产品.这就是为什么关系为零或者1.当一个产品为畅销产品时,与之关联的topSelling实体包含一个用户评级.你想查找和呈现所有的产品,和与之

《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述 (转)

微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF版本更新太快,没人愿意去花时间翻译国外关于EF的书籍.使用Entity Framework开发已经有3年多了,但用得很肤浅,最近想深入学习,只好找来英文书<Entity Framework 6 Recipes>第二版,慢慢啃.首先需要说明的是,我英文不好,只是为了学习EF.把学习的过程写成博客,一