本章节讲解EF里的继承映射关系,分为TPH、TPT、TPC。具体:

1.TPH:Table Per Hierarchy

这是EF的默认的继承映射关系:一张表存放基类和子类的所有列,自动生成的discriminator列用来区分基类和子类的数据。新建一个度假村Resort实体类试试:

    /// <summary>
/// 度假村类
/// </summary>
public class Resort : Lodging //这里继承了Lodging类
{
public string Entertainment { get; set; } //娱乐
public string Activities { get; set; } //活动
}

之前的住宿类Lodging里有个属性IsResort表示是否度假胜地,现在可以注释掉了,有新的类Resort来继承Lodging表示是否是度假胜地了,跑下程序最终会生成一张表:

并没有生成Resorts表,而是把Resrot实体类里的属性生成到了Lodgings表里。多了一列discriminator,这个是默认的,用来表示数据来自哪个类,继续添加一个插入Lodging表数据的方法:

        private static void InsertLodging()
{
var lodging = new CodeFirst.Model.Lodging
{
Name = "Rainy Day Motel",
Destination = new CodeFirst.Model.Destination
{
Name = "Seattle, Washington",
Country = "USA"
}
};
using (var context = new CodeFirst.DataAccess.BreakAwayContext())
{
context.Lodgings.Add(lodging);
context.SaveChanges();
}
}

再添加一个插入Resort表数据的方法:

        private static void InsertResort()
{
var resort = new CodeFirst.Model.Resort
{
Name = "Top Notch Resort and Spa",
MilesFromNearestAirport = 30,
Activities = "Spa, Hiking, Skiing, Ballooning",
Destination = new CodeFirst.Model.Destination
{
Name = "Stowe, Vermont",
Country = "USA"
}
};
using (var context = new CodeFirst.DataAccess.BreakAwayContext())
{
context.Lodgings.Add(resort);
context.SaveChanges();
}
}

在Main方法里调用两个插入方法,可得到如下数据:

两个插入的数据都到了一张表里。Discriminator列表示数据来自哪一列。当然是可以配置的,这里就必须使用Fluent API配置了,Data Annotation表示无能为力,到LodgingMap里进行配置:

this.Map<CodeFirst.Model.Lodging>(l => { l.Requires("From").HasValue("Standard"); });
this.Map<CodeFirst.Model.Resort>(l => { l.Requires("From").HasValue("Resort"); });

生成了我们指定的From列,数据Standard、Resort分别表示来自Lodging和Resrot表,形象点就是1号酒店是普通酒店,2号就是是度假胜地的酒店:

当然,这里甚至可以把HasValue方法里的参数设置成True和False,用布尔类型的数据区分普通酒店和度假胜地的酒店更形象,园友lk8167给了一个更形象的普通售货员和销售经理的例子

2.TPT:Table Per Type

父类和子类在不同的表里。使用Data Annotation配置TPT:

[Table("Resorts")]
public class Resort : Lodging
{
public string Entertainment { get; set; }
public string Activities { get; set; }
}

或者使用Fluent API配置:

            this.Map(m =>
{
m.ToTable("Lodgings");
}).Map<CodeFirst.Model.Resort>(m =>
{
m.ToTable("Resorts");
});

注意:上面配置TPH的Fluetn API需要注释掉在跑程序,那是测试TPH的配置。同时释放这句的注释:context.Database.Initialize(true);,这里没修改实体,但是也需要重新生成数据库。最终数据库是这样的:

父类和子类实体都有一张表,子表通过主键LodgingId找到父表:

3.TPC:Table Per Concrete Type

为每个子类建立一个表,每个与子类对应的表中包含基类的属性对应的列和子类特有属性对应的列。同样之前配置TPT的Fluent API需要先注释掉,然后我们通过Fluent API配置下TPC,TPC也无法用Data Annotation配置:

         this.Map(m =>
{
m.ToTable("Lodgings");
}).Map<CodeFirst.Model.Resort>(m =>
{
m.ToTable("Resorts");
m.MapInheritedProperties();
});

生成的数据库:

可见,子类Resorts类也有了基类的所有属性。

注意:为了方便测试生成TPC,我注释了所有Lodging表的导航属性,主要是和Destination的一对多关系、Destination类也需要注释掉Lodging属性和Fluent API关系配置,否则程序跑起来会报DataException错:

An exception occurred while initializing the database. See the InnerException for details.

大家下载demo使用的时候也需要先注释掉Lodging类的导航属性。当然不注释想保留也可以,必须设置外键为可空类型,具体请参考Programming Entity Framework: Code First 第五章 Avoiding Mapping Exceptions with TPC

讲了这几种方式配置继承映射,实际项目中应该用哪个呢?

  1. 不推荐使用TPC(Type Per Concrete Type),因为在TPC方式中子类中包含的其他类的实例或实例集合不能被映射为表之间的关系。你必须通过手动地在类中添加依赖类的主键属性,从而让 Code First感知到它们之间的关系,而这种方式是和使用Code First的初衷相反的;
  2. 从查询性能上来说,TPH会好一些,因为所有的数据都存在一个表中,不需要在数据查询时使用join;
  3. 从存储空间上来说,TPT会好一些,因为使用TPH时所有的列都在一个表中,而表中的记录不可能使用所有的列,于是有很多列的值是null,浪费了很多存储空间;
  4. 从数据验证的角度来说,TPT好一些,因为TPH中很多子类属性对应的列是可为空的,就为数据验证增加了复杂性。

摘自这里,本文源码

本系列文章结束,主要讲解了EF里如何使用Code First的方式配置数据库,基本上都是手写的配置,其实大家可能已经想到会有工具可以自动配置这些关系了,对了,就是EF Power Tools。这个工具相当智能,可以直接配置出所有的关系。不过个人还是建议关系不多的话自己手写Fluent API来配置。

另外,前面配置了那么长时间的一对多、多对多等各种关系。配置好了如何用EF对这些数据进行增查改查呢?后续还会有系列文章讲解EF是如何操作数据库的,请保持关注。

EF Code First 系列文章导航

  1. EF Code First 初体验
  2. EF里的默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射 本节源码
  3. EF里Guid类型数据的自增长、时间戳和复杂类型的用法 本节源码
  4. EF里一对一、一对多、多对多关系的配置和级联删除 本节源码
  5. EF里的继承映射关系TPH、TPT和TPC的讲解以及一些具体的例子 本节源码

 

 

原文地址:http://www.cnblogs.com/oppoic/p/ef_tph_tpt_tpc_inheritance.html

entity framework里的继承映射关系TPH、TPT和TPC的更多相关文章

  1. EF里的继承映射关系TPH、TPT和TPC的讲解以及一些具体的例子

    本章节讲解EF里的继承映射关系,分为TPH.TPT.TPC.具体: 1.TPH:Table Per Hierarchy 这是EF的默认的继承映射关系:一张表存放基类和子类的所有列,自动生成的discr ...

  2. EF——继承映射关系TPH、TPT和TPC的讲解以及一些具体的例子 05 (转)

    EF里的继承映射关系TPH.TPT和TPC的讲解以及一些具体的例子   本章节讲解EF里的继承映射关系,分为TPH.TPT.TPC.具体: 1.TPH:Table Per Hierarchy 这是EF ...

  3. 继承映射关系 TPH、TPT、TPC<EntityFramework6.0>

    每个类型一张表[TPT] 声明方式 public class Business { [Key] public int BusinessId { get; protected set; } public ...

  4. 在Entity Framework 中实现继承关系映射到数据库表

    继承关系映射到数据库表中有多种方式: 第一种:TPH(table-per-hiaerachy) 每一层次一张表 (只有一张表) 仅使用名为父类的类型名的一张表,它包含了各个子类的所有属性信息,使用区分 ...

  5. Entity Framework Code First属性映射约定

    Entity Framework Code First与数据表之间的映射方式有两种实现:Data Annotation和Fluent API.本文中采用创建Product类为例来说明tity Fram ...

  6. 补习知识:Entity Framework Code First属性映射约定

    Entity Framework Code First与数据表之间的映射方式有两种实现:Data Annotation和Fluent API.本文中采用创建Product类为例来说明tity Fram ...

  7. Entity Framework Code First属性映射约定 转载https://www.cnblogs.com/libingql/p/3352058.html

    Entity Framework Code First属性映射约定   Entity Framework Code First与数据表之间的映射方式有两种实现:Data Annotation和Flue ...

  8. hibernate 继承映射关系( SINGLE_TABLE)

    三种继承映射关系.   1,SINGLE_TABLE   person student  teacher 在一个表中,student和teacher继承自person,通过一个Discriminato ...

  9. Entity Framework多对多关联映射的实现

    Entity Framework是微软官方提供的一个ORM解决方案,它有纯正的血统,比NHibernate更容易使用并且与现有其它官方框架配合更加密切. 时代不断的在发展变化,记得10年前还是ADO( ...

随机推荐

  1. (转)深入理解javascript的function

    原文:http://www.cnblogs.com/sharpxiajun/archive/2011/09/16/2179323.html javascript笔记:深入理解javascript的fu ...

  2. 2016 - 1 - 19NSOpertation的依赖关系和监听

    一:NSOperation的依赖: 1.概念:队列中的A操作需要等其他B操作或者某些操作执行完毕后才执行,就叫做A依赖与B或者A依赖于其他某些操作. 2.注意点:不能循环依赖,否则卡死.如: [op2 ...

  3. python 优雅的使用正则表达式 ~ 2

    使用正则表达式 那些基础的理论也说了不少了现在就开始 实操 ( 不知道为啥特别喜欢这个词... ) 吧 . 上一节课说过 正则表达式也是一门语言 , 他被集成到了python当中 , 并且用 re 模 ...

  4. Python 字符串处理大全.

    Python 字符串 字符串是Pyhton中常用的数据类型,我们可以使用引号来创建字符串 . 创建字符串很简单 , 就不说了 . Python 访问字符串中的值 鬼叔本着简洁 使用的设计目的 , 在设 ...

  5. python3爬虫初探(二)之requests

    关于请求网页,不得不提requests这个库,这是爬虫经常用到的一个第三方库,用pip安装即可. requests用法很多,这里只写一些基础的,其他高级功能可参考官方文档. import reques ...

  6. Mac快捷键 Xcode快捷键

    Mac OSX 快捷键&命令行   一.Mac OSX 快捷键 ctrl+shift                                    快速放大dock的图标会暂时放大,而 ...

  7. 17、SQL基础整理(事务)

    事务 事务==流程控制 确保流程只能成功或者失败,若出现错误会自动回到原点 例: begin tran insert into student values('111','王五','男','1999- ...

  8. [转]Golang Gob编码

    Golang Gob编码 2012-08-24 09:47 by 轩脉刃, 5119 阅读, 1 评论, 收藏, 编辑 gob是Golang包自带的一个数据结构序列化的编码/解码工具.编码使用Enco ...

  9. C# 控件聚焦

    /********************************************************************** * C# 控件聚焦 * 说明: * 做界面经常需要将ta ...

  10. yii弹出层

    Yii弹出层,包装了JQuery的JDialog,使用很方便.Yii组件功能太强大,强大到无法自拔 $this->beginWidget('zii.widgets.jui.CJuiDialog' ...