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

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

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

1.TPH:Table Per Hierarchy数据库

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

复制代码

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

复制代码

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

并无生成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里进行配置:ui

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号就是是度假胜地的酒店:this

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

2.TPT:Table Per Type

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

按 Ctrl+C 复制代码

按 Ctrl+C 复制代码

或者使用Fluent API配置:

按 Ctrl+C 复制代码

按 Ctrl+C 复制代码

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

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

3.TPC:Table Per Concrete Type

为每一个子类创建一个表,每一个与子类对应的表中包含基类的属性对应的列和子类特有属性对应的列。一样以前配置TPT的Fluent API须要先注释掉,而后咱们经过Fluent API配置下TPC,TPC也没法用Data Annotation配置:

按 Ctrl+C 复制代码

按 Ctrl+C 复制代码

生成的数据库:

可见,子类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里一对1、一对多、多对多关系的配置和级联删除 本节源码
  5. EF里的继承映射关系TPH、TPT和TPC的讲解以及一些具体的例子 本节源码
相关文章
相关标签/搜索