翻译的初衷以及为什么选择《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

  public abstract class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
} public class SalariedEmployee : Employee
{
public decimal? Salary { get; set; }
} public class CommissionedEmployee : SalariedEmployee
{
public decimal? Commission { get; set; }
} public class HourlyEmployee : Employee
{
public decimal? Rate { get; set; }
public decimal? Hours { get; set; }
}
}

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

    4、在上下文对象中重写OnModelCreating方法,配置TPH中每个派生类的鉴别值,如代码清单6-24所示;

代码清单6-24. 重写OnModelCreating方法,配置TPH中每个派生类的鉴别值

   protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder); modelBuilder.Entity<Employee>()
.HasKey(e => e.EmployeeId)
.Property(e => e.EmployeeId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); modelBuilder.Entity<Employee>()
.Map<HourlyEmployee>(m => m.Requires("EmployeeType").HasValue("hourly"))
.Map<SalariedEmployee>(m => m.Requires("EmployeeType").HasValue("salaried"))
.Map<CommissionedEmployee>(m => m.Requires("EmployeeType").HasValue("commissioned"))
.ToTable("Employee", "Chapter6");
}

原理

  TPH继承映射是一种灵活的建模技术。继承树的深度和广度可以进行合理地扩展,映射也容易实现。这种方法有效率,是因为它没有引入额外的表,不涉及join连接。

  使用Code-First来实现TPH简单明了,因为面向对象的继承,层次自然。

  代码清单6-25演示了从模型中插入和获取。

代码清单6-25.插入并获取Employee的派生类型

  using (var context = new Recipe8Context())
{
var hourly = new HourlyEmployee
{
Name = "Will Smith",
Hours = (decimal),
Rate = 7.75M
};
var salaried = new SalariedEmployee
{
Name = "JoAnn Woodland",
Salary = 65400M
};
var commissioned = new CommissionedEmployee
{
Name = "Joel Clark",
Salary = 32500M,
Commission = 20M
};
context.Employees.Add(hourly);
context.Employees.Add(salaried);
context.Employees.Add(commissioned);
context.SaveChanges();
} using (var context = new Recipe8Context())
{
Console.WriteLine("All Employees");
Console.WriteLine("=============");
foreach (var emp in context.Employees)
{
if (emp is HourlyEmployee)
Console.WriteLine("{0} Hours = {1}, Rate = {2}/hour",
emp.Name,
((HourlyEmployee)emp).Hours.Value.ToString(),
((HourlyEmployee)emp).Rate.Value.ToString("C"));
else if (emp is CommissionedEmployee)
Console.WriteLine("{0} Salary = {1}, Commission = {2}%",
emp.Name,
((CommissionedEmployee)emp).Salary.Value.ToString("C"),
((CommissionedEmployee)emp).Commission.ToString());
else if (emp is SalariedEmployee)
Console.WriteLine("{0} Salary = {1}", emp.Name,
((SalariedEmployee)emp).Salary.Value.ToString("C"));
}
}

代码清单6-25的输出如下:

All Employees
=============
Will Smith Hours = 39.00, Rate = $7.75/hour
JoAnn Woodland Salary = $,400.00
Joel Clark Salary = $,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. 从模型中插入和获取数据

  using (var context = new Recipe9Context())
{
context.Database.ExecuteSqlCommand(@"insert into chapter6.toy
(Name,ForDonationOnly) values ('RagDoll',1)");
var toy = new Toy { Name = "Fuzzy Bear", Price = 9.97M };
var refurb = new RefurbishedToy
{
Name = "Derby Car",
Price = 19.99M,
Quality = "Ok to sell"
};
context.Toys.Add(toy);
context.Toys.Add(refurb);
context.SaveChanges();
} using (var context = new Recipe9Context())
{
Console.WriteLine("All Toys");
Console.WriteLine("========");
foreach (var toy in context.Toys)
{
Console.WriteLine("{0}", toy.Name);
}
Console.WriteLine("\nRefurbished Toys");
foreach (var toy in context.Toys.OfType<RefurbishedToy>())
{
Console.WriteLine("{0}, Price = {1}, Quality = {2}", toy.Name,
toy.Price, ((RefurbishedToy)toy).Quality);
}
}

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

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

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

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-6  映射派生类中的NULL条件 问题 你的表中,有一列允许为null.你想使用 ...

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

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-11  TPH继承映射中使用复合条件 问题 你想使用TPH为一张表建模,建模中使 ...

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

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第六章  继承与建模高级应用 现在,你应该对实体框架中基本的建模有了一定的了解,本章 ...

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

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-4  使用TPH建模自引用关系 问题 你有一张自引用的表,它代表数据库上不同类型 ...

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

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-10  创建一个多条件过滤 问题 你想使用多个条件为实体过滤表中的行. 解决方案 ...

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

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-12  TPC继承映射建模 问题 你有两张或多张架构和数据类似的表,你想使用TP ...

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

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-13  在基类中应用条件 问题 你想从一个已存在的模型中的实体派生一个新的实体, ...

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

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-10应用左连接 问题 你想使用左外连接来合并两个实体的属性. 解决方案 假设你有 ...

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

    微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...

随机推荐

  1. PowerDesigner修改生成mysql视图

    今天遇到了个问题,就是有PowerDesigner的设计图,能生成oracle的视图,不能生成mysql,在网上找到了解决方案, 非常感谢各位网友的分享,这个不是抄袭,主要是为了让更多的人知道这种解决 ...

  2. 转: Delphi的OverRide、OverLoad和Virtual方法

    http://blog.csdn.net/ckli/article/details/2201418 override 重写 也叫覆盖 .方法的重写Overriding和重载Overloading是Ja ...

  3. Material Design兼容包的使用

    为了方便自己以后的查找,于是就写了这个博客,废话就不多说,开始干: 导入: compile 'com.android.support:appcompat-v7:24.2.1' compile 'com ...

  4. POJ3461 KMP 模板题

    最近忙着考研复习,所以刷题少了.. 数据结构昨天重新学习了一下KMP算法,今天自己试着写了写,问题还不少,不过KMP算法总归是理解了,以前看v_JULY_v的博客,一头雾水,现在终于懂了他为什么要在算 ...

  5. 时代杂志发文:2017 AR/MR将变得比VR更加重要

    每到年末都有很多企业或高管分析科技产业明年趋势.近日,时代杂志网页版刊登了2017年科技行业的五大趋势和热点话题的预测.该本作者TimBajarin,是硅谷市场研究公司CreativeStrategi ...

  6. BZOJ3197 & 组合乱搞

    Description    求\[\sum_{i = 1}^{n}i^m m^i , m \leq 1000 \] 的值.Solution    From Miskcoo's Space:      ...

  7. Android 照相 滤镜

    android-image-filter 19种相片滤镜,使用也简单,all filters in file BitmapFilter.java : Bitmap newBitmap = Bitmap ...

  8. [ACM训练] 算法初级 之 数据结构 之 栈stack+队列queue (基础+进阶+POJ 1338+2442+1442)

    再次面对像栈和队列这样的相当基础的数据结构的学习,应该从多个方面,多维度去学习. 首先,这两个数据结构都是比较常用的,在标准库中都有对应的结构能够直接使用,所以第一个阶段应该是先学习直接来使用,下一个 ...

  9. bzoj1026数位dp

    基础的数位dp 但是ce了一发,(abs难道不是cmath里的吗?改成bits/stdc++.h就过了) #include <bits/stdc++.h> using namespace ...

  10. PHP多级联动的学习(一)

    我尝试在ThinkCMF中实现多级联动,首先我开始看了dede的联动类别管理前后台的代码以及他的数据库,经过非常多次的尝试,我渐渐有了一点想法,并给予实施. 首先写出前台的界面.如图. 然后在数据库中 ...