Entity Framework映射TPH、TPT、TPC与继承类
作者:springsnow 发布时间:2022-10-18 04:52:52
一、TPH
Table Per Hierarchy (默认,每个层次一个表)
每个层次结构共用一个表,类的每一个属性都必须是可空的。
1、默认行为
只建立一个表,把基类和子类中的所有属性都映射为表中的列。
为基类和所有子类共建立一个表,基类和子类中的所有属性都映射为表中的一个列。
默认在这个表中建立一个叫做Discriminator的列,类型是nvarchar,长度是128。在存储基类或子类的时候,把类名作为Discriminator列的值。
2、Fluent API修改默认行为
Map方法中传入的类型参数是子类的类名,Requires用于指定Discriminator列的名字,HasValue用于指定它的类型和每个子类对应的值。
modelBuilder.Entity<Course>()
.Map<Course>(m => m.Requires("Type").HasValue("Course"))
.Map<OnsiteCourse>(m => m.Requires("Type").HasValue("OnsiteCourse"));
二、TPT
Table Per Type(每个类各一个表)
1、默认行为
为基类和每个子类各建立一个表,每个与子类对应的表中只包含子类特有的属性对应的列。
子类的表中只包含子类特有的属性,子表还会存储一个将子表与基表联接的外键。
2、Fluent API修改默认行为
我们可以使用Map方法强制让Code First使用TPT方式,因为Code First默认使用的是TPH方式。
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<OnsiteCourse>().ToTable("OnsiteCourse");
三、TPC
Table Per ConCrete Type(每个具体类型各一个表)
每个具体的派生类各一个表,没有基表。不推荐使用。
1、默认行为
在子类对应的表中除了子类特有的属性外还有基类的属性对应的表。基类可以是abstract。
2、Fluent API修改默认行为
通过MapInheritedProperties方法就可以强制Code First使用TPC方式。
注意:因为属于 TPC 继承层次结构的表并不使用同一个主键, 关闭主键属性的标识,避免为不同子表插入重复的实体键。
modelBuilder.Entity<Course>()
.Property(c => c.CourseID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder.Entity<OnsiteCourse>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("OnsiteCourse");
});
modelBuilder.Entity<OnlineCourse>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("OnlineCourse");
});
四、实体拆分
允许一个实体类型的属性分散在多个表中。
实体拆分通过多次调用 Map 方法将一部分属性映射到特定表。
在以下示例中,Department 实体拆分到两个表中:Department 和 DepartmentDetails。
modelBuilder.Entity<Department>()
.Map(m =>
{
m.Properties(t => new { t.DepartmentID, t.Name });
m.ToTable("Department");
}).
Map(m =>
{
m.Properties(t => new { t.DepartmentID, t.Administrator, t.StartDate, t.Budget });
m.ToTable("DepartmentDetails");
});
五、表拆分
两个实体类型映射到同一个表。
1.两个类必须共享同一个主键。
2.两个类之间的关系必须被映射为表之间的一对一关系。
modelBuilder.Entity<OfficeAssignment>().HasKey(t => t.InstructorID); //共用主键
modelBuilder.Entity<Instructor>() .HasRequired(t => t.OfficeAssignment).WithRequiredPrincipal(t => t.Instructor);//一对一关系
modelBuilder.Entity<Instructor>().ToTable("Instructor");
modelBuilder.Entity<OfficeAssignment>().ToTable("Instructor");
六、将类指定为复杂类型
1、指定方法:
DataAnnotations方式:
[ConlexType]
public Details details;
或FluentAPI:
modelBuilder.ComplexType<Details>();
注意:
1.复杂类型类不能有主键。
2.复杂类型只能包含.net基础类型的属性。
3.使用复杂类型的类,只能包复杂类型的一个实例,不能使用复杂类型的集合。
2、配置复杂类型的属性
(1)、可以对 ComplexTypeConfiguration 调用 Property。
modelBuilder.ComplexType<Details>() .Property(t => t.Location).HasMaxLength(20);
或
public class AddressComplexTypeConfiguration:ComplexTypeConfiguration<Address>
{
public AddressComplexTypeConfiguration()
{
Property(a => a.Country).HasColumnName("Country").HasMaxLength(100);
Property(a => a.ZipCode).HasColumnName("ZipCode").HasMaxLength(6);
}
}
(2)、也可以使用点表示法访问复杂类型的属性。
modelBuilder.Entity<OnsiteCourse>().Property(t => t.Details.Location) .HasMaxLength(20);
七、DataBase初始化
1、调用Database.SetInitializer方法:
一般Global.ascx.cs,Main应用程序的入口等地方调用Database.SetInitializer方法:
只要Fluent API配置的数据库映射发生变化或者domain中的model发生变化了,就把以前的数据库删除掉,根据新的配置重新建立数据库。
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<BreakAwayContext>());
只有在没有数据库的时候才会根据数据库连接配置创建新的数据库。这种配置主要用于production环境。
Database.SetInitializer(new CreateDatabaseIfNotExists<BreakAwayContext>());
不管数据库映射或者model是否发生变化,每次都重新删除并根据配置重建数据库。
Database.SetInitializer(new DropCreateDatabaseAlways<BreakAwayContext>());
2、通过配置文件更灵活的指定数据库初始化的方式:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="DatabaseInitializerForTypeOrderSystemContext" value="System.Data.Entity.DropCreateDatabaseIfModelChanges[[OrderSystemContext]], EntityFramework" />
</appSettings>
</configuration>
3、自定义数据库初始化类
通过自定的初始化类,还可以将一些基础数据在创建数据库之后插入到数据库中去。
public class DropCreateOrderDatabaseWithSeedValueAlways : DropCreateDatabaseAlways<OrderSystemContext>
{
protected override void Seed(OrderSystemContext context)
{
context.ProductCatalogs.Add(new ProductCatalog { CatalogName = "DELL E6400", Manufactory = "DELL", ListPrice = 5600, NetPrice = 4300 });
context.ProductCatalogs.Add(new ProductCatalog { CatalogName = "DELL E6420", Manufactory = "DELL", ListPrice = 7000, NetPrice = 5400 });
}
}
Database.SetInitializer(new DropCreateOrderDatabaseWithSeedValueAlways());
来源:https://www.cnblogs.com/springsnow/p/13230102.html


猜你喜欢
- 一、基于 Windows 的标准计时器(System.Windows.Forms.Timer)首先注意一点就是:Windows 计时器是为单
- 将Object类转换为实体类问题描述在用SpringBoot写controller的时候,需要接受一个map的Object,之后要把Obje
- 前言属于基础的面试问题,一定要能够回答全哦~一、继承Thread,重写run方法通过自定义一个类(这里起名为:MyThread),继承Thr
- 一、事务隔离级别①介绍数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事 务与其他事务隔离的程度称为
- 本文实例讲述了C#禁止textbox复制、粘贴、剪切及鼠标右键的方法。分享给大家供大家参考。具体如下:class MyTextBox : S
- DAO模式是接口的一个典型应用。1. StudenDaoListImpl.java与StudentDaoArrayImpl.java有何不同
- 前言我们一说到spring,可能第一个想到的是 IOC(控制反转) 和 AOP(面向切面编程)。没错,它们是spring的基石,得益于它们的
- 一、饿汉式单例类public class Singleton { privat
- Java的super关键字当子类重写父类的方法后,子类对象将无法直接访问父类被重写的方法。为了解决这个问题,在Java中专门提供了一个sup
- 好久没有写文章了,下面把自己最近程序中用到的一个小小的导出文件的方法给在家分享一下,欢迎大家来排砖,谢谢~不说废话了,直接上代码:using
- 在上一篇文章中,我们实现了统计每个产品和地区的销售额,如果现在需要统计每个产品和地区所占市场份额的百分比,那么使用堆叠条形图是不合适的,我们
- 本文实例为大家分享了Unity Shader序列帧动画效果的具体代码,供大家参考,具体内容如下 实现原理主要的思想是设置显示UV
- spring的一大功能是依赖注入 通过把javabean放入spring的ioc容器中进行统一管理过程如图所示最常见的例子是使用xml配置b
- 本文实例讲述了C#转换日期类型的方法。分享给大家供大家参考。具体分析如下:如:将日期1999-5-31 11:20转换成 /Date(928
- 本章节更加具体化的学习编译器还有哪些可以优化的方便,让你的应用展现出更好的性能。JIT编译器版本JIT编译器有不同的版本,而最终你使用哪种,
- 1.通过用FTP进行上传文件,首先要实现建立FTP连接,一般建立FTP连接,需要知道FTP配置有关的信息。一般要在Bean中建立一个Serv
- 项目中要使用到在线支付功能 目前常用的在线支付手段主要是 支付宝 和微信。 这里我使用的是支付宝支付,支付宝有个好处就是他有一个沙箱模式 即
- XSS是一种经常出现在web应用中的计算机安全漏洞,具体信息请自行Google。本文只分享在Spring Cloud Gateway中执行通
- 前言:最近涉及到和QQ打交道,定义所有的好友一共只能有300条消息,如果一次性从数据库读取300条或者更多,界面会有细微的卡顿.所以考虑了下
- 一、JAVA常用APIjava.lang.Math提供sin, cos, tan, exp, log, log10 等类方法,PI和E等类字