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

摘要:
本章解释EF中的继承映射关系,包括TPH、TPT和TPC。具体来说:1.TPH:TablePerHierarchy这是EF的默认继承映射关系:一个表存储基类和子类的所有列,自动生成的鉴别器列用于区分基类和子类别的数据。鉴别器列表显示数据来自哪一列。最终的数据库如下:父类和子类实体有一个表,子表通过主键LodgingId:3找到父表。TPC:TablePerConcreteType为每个子类创建一个表,并且对应于子类的每个表包含对应于基类的属性的列和对应于子类别的特定属性的列。

本章节讲解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表示是否是度假胜地了,跑下程序最终会生成一张表:

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

并没有生成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方法里调用两个插入方法,可得到如下数据:

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

两个插入的数据都到了一张表里。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号就是是度假胜地的酒店:

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

当然,这里甚至可以把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);,这里没修改实体,但是也需要重新生成数据库。最终数据库是这样的:

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

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

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

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();
            });

 生成的数据库:

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

可见,子类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的讲解以及一些具体的例子  本节源码

免责声明:文章转载自《EF里的继承映射关系TPH、TPT和TPC的讲解以及一些具体的例子》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SQL Server 2014 中新建登录及权限分配【界面版】在vue中使用animate.css下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

EFCore数据库迁移命令整理

因为现在用.net core 开发新项目,过程中需要经常涉及到数据命令的迁移,今天分别整EFCore 的两种迁移数据库的方式  1 程序包管理器控制台 , Package Manager Console(PMC)        -如果你用visual studio 开发建议使用PMC迁移方式,该方式是同时支持efcore和原先的ef 迁移的 2 命令行工具...

EntityFramework的多种记录日志方式,记录错误并分析执行时间过长原因(系列4)

Entity Framework 延伸系列目录 今天我们来聊聊EF的日志记录. 一个好的数据库操作记录不仅仅可以帮你记录用户的操作, 更应该可以帮助你获得效率低下的语句来帮你提高运行效率 废话不多说,我们开始 环境和相关技术 本文采用的环境与技术 系统:WIN7 数据库:SQL Server2008 相关技术:MVC5 EF6.0+ 简单的记录 一、修改...

Code First :使用Entity. Framework编程(4)

井底之蛙  博客园 首页 博问 闪存 新随笔 联系 订阅 管理 随笔- 35  文章- 0  评论- 2  Code First :使用Entity. Framework编程(4)  第4章 对关系使用默认规则与配置 在第3章,你已经掌握了默认规则与配置对属性以及其在数据库映射的字段的影响。在本章,我们把焦点放在类之间的关系上面。这包括类...

Asp.net Mvc 使用EF6 code first 方式连接MySQL总结

最近由于服务器变更为Linux系统.MsSql for Linux什么时候出来到生产环境使用还是要很长时间的.于是考虑使用Mysql数据库,ORM使用EF.于是先踩下坑顺便记录一下,有需要的tx可以参考下.当你考虑使用EF连接Mysql的时候肯定是已经在网上搜了一堆教程.网上教程基本都是使用控制台做演示.跟着一步步来姿势没错的话可能会正常运行,但项目中使用...

Asp.net 面向接口可扩展框架之数据处理模块及EntityFramework扩展和Dapper扩展(含干货)

接口数据处理模块是什么意思呢?实际上很简单,就是使用面向接口的思想和方式来做数据处理。 还提到EntityFramework和Dapper,EntityFramework和Dapper是.net环境下推崇最高的两种ORM工具。 1、EntityFramework是出自微软根正苗红的.net下的ORM工具,直接在Vs工具和Mvc框架中集成了,默认生成的项目就...

[转]EntityFramework Core技术线路(EF7已经更名为EF Core,并于2016年6月底发布)

本文转自:http://www.cnblogs.com/VolcanoCloud/p/5572408.html 官方文档英文地址:https://github.com/aspnet/EntityFramework/wiki/Roadmap 历经延期和更名,新版本的实体框架终于要和大家见面了,虽然还有点害羞。请大家多体谅! 下面正式进入主题: Entity...