上篇链接:EF学习笔记(十) 处理并发

本篇原文链接:Implementing Inheritance

面向对象的世界里,继承可以很好的重用代码。在本章就对Instructor和Student两个类进行实施继承处理,这两个类有公用的属性,比如LastName等,也有私有的属性;

可以不用增加任何页面,进行修改一些代码,这些修改后的继承关系就会自动反应到数据库中。

通过下图可以看到两个类有哪些公用属性:

那么就可以建一个Person的基础类,让这两个类继承自Persion类:

Options for mapping inheritance to database tables

映射继承到数据库表有以下3种方式:

TPH: table-per-hierarchy

在数据库里就建一个表,里面除了有公有的字段外,既有Student的私有字段,也有Instructor的私有字段;然后再加上一个辨别字段(discriminator)来标明本行是Student还是Instructor,如下图:

TPT: table per type

在数据库里为基础类、继承后的类各生成一张表,表结构就和继承关系一样;

TPC: Table-per-Concrete

就是把所有非抽象的属性都定义到表中,包括来自继承的基类属性;这种方式生成的数据库表就可以和前面没有写继承的时候是一样的;

TPC 和TPH 理论上会有比较好的性能,因为TPT会有大量复杂的SQL Join的操作;

本篇只讲述TPH,TPT和TPC可通过以下链接学习:

Mapping the Table-Per-Type (TPT) Inheritance

Mapping the Table-Per-Concrete Class (TPC) Inheritance

实践操作

先新建一个Person基类:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; namespace EFTest.Models
{
public abstract class Person
{
public int ID { get; set; } [Required]
[StringLength()]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Required]
[StringLength(, ErrorMessage = "First name cannot be longer than 50 characters.")]
[Column("FirstName")]
[Display(Name = "First Name")]
public string FirstMidName { get; set; } [Display(Name = "Full Name")]
public string FullName
{
get
{
return LastName + ", " + FirstMidName;
}
}
}
}

然后修改Student和Instructor类,继承自Person类,去除部分代码:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; namespace EFTest.Models
{
public class Instructor : Person
{
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Hire Date")]
public DateTime HireDate { get; set; } public virtual ICollection<Course> Courses { get; set; }
public virtual OfficeAssignment OfficeAssignment { get; set; } }
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; namespace EFTest.Models
{
public class Student:Person
{
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Enrollment Date")]
public DateTime EnrollmentDate { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; }
} }

SchoolContext.cs中增加:

public DbSet<Person> People { get; set; }

下面就开始迁移数据库,在PMC输入: Add-Migration Inheritance
如果这个时候,直接运行 update-database 会有报错,主要是因为有一些外键存在;

在XXXXXXXX_Inheritance.sc中的up方法中加入以下处理代码:

红色字部分为增加的,注意插入的顺序,

主要工作就是删除原有外键,然后增加一列临时列,把原有Student数据放到新表来;

然后把原来的Enrollement的外键值更新一下,变为新的ID值,再把临时列删除,最后把外键和索引重新再建立:

        public override void Up()
{
// Drop foreign keys and indexes that point to tables we're going to drop.
DropForeignKey("dbo.Enrollment", "StudentID", "dbo.Student");
DropIndex("dbo.Enrollment", new[] { "StudentID" }); RenameTable(name: "dbo.Instructor", newName: "Person");
AddColumn("dbo.Person", "EnrollmentDate", c => c.DateTime());
AddColumn("dbo.Person", "Discriminator", c => c.String(nullable: false, maxLength: ));
AlterColumn("dbo.Person", "HireDate", c => c.DateTime()); AddColumn("dbo.Person", "OldId", c => c.Int(nullable: true)); // Copy existing Student data into new Person table.
Sql("INSERT INTO dbo.Person (LastName, FirstName, HireDate, EnrollmentDate, Discriminator, OldId) SELECT LastName, FirstName, null AS HireDate, EnrollmentDate, 'Student' AS Discriminator, ID AS OldId FROM dbo.Student"); // Fix up existing relationships to match new PK's.
Sql("UPDATE dbo.Enrollment SET StudentId = (SELECT ID FROM dbo.Person WHERE OldId = Enrollment.StudentId AND Discriminator = 'Student')"); // Remove temporary key
DropColumn("dbo.Person", "OldId"); DropTable("dbo.Student"); // Re-create foreign keys and indexes pointing to new table.
AddForeignKey("dbo.Enrollment", "StudentID", "dbo.Person", "ID", cascadeDelete: true);
CreateIndex("dbo.Enrollment", "StudentID"); }

最后执行下 update-database:
最后看看数据库的结果:

最后数据库的结构变为:

【EF6学习笔记】(十一)实施继承的更多相关文章

  1. 【EF6学习笔记】目录

    [EF6学习笔记](一)Code First 方式生成数据库及初始化数据库实际操作 [EF6学习笔记](二)操练 CRUD 增删改查 [EF6学习笔记](三)排序.过滤查询及分页 [EF6学习笔记]( ...

  2. ASP.NET MVC5 及 EF6 学习笔记 - (目录整理)

    个人从传统的CS应用开发(WPF)开始转向BS架构应用开发: 先是采用了最容易上手也是最容易搞不清楚状况的WebForm方式入手:到后面就直接抛弃了服务器控件的开发方式,转而采用 普通页面+Ajax+ ...

  3. EF6学习笔记(四) 弹性连接及命令拦截调试

    EF6学习笔记总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 本章原文地址:Connection Resiliency and Command Interception 原文 ...

  4. EF6 学习笔记(一):Code First 方式生成数据库及初始化数据库实际操作

    EF6 学习笔记总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 本篇参考原文地址: Creating an Entity Framework Data Model 说明:学习 ...

  5. EF6学习笔记(六) 创建复杂的数据模型

    EF6学习笔记总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 本篇原文地址:Creating a More Complex Data Model 本篇讲的比较碎,很多内容本人 ...

  6. EF6 学习笔记(五):数据库迁移及部署

    EF6学习笔记总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 原文地址:Code First Migrations and Deployment 原文主要讲两部分:开发环境下 ...

  7. EF6 学习笔记(三):排序、过滤查询及分页

    EF6 学习笔记索引目录页: ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 上篇:EF6 学习笔记(二):操练 CRUD 增删改查 本篇原文地址:Sorting, Filterin ...

  8. EF6 学习笔记(二):操练 CRUD 增删改查

    EF6学习笔记总目录 ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 接上篇: EF6 学习笔记(一):Code First 方式生成数据库及初始化数据库实际操作 本篇原文链接: I ...

  9. python3.4学习笔记(十一) 列表、数组实例

    python3.4学习笔记(十一) 列表.数组实例 #python列表,数组类型要相同,python不需要指定数据类型,可以把各种类型打包进去#python列表可以包含整数,浮点数,字符串,对象#创建 ...

  10. Go语言学习笔记十一: 切片(slice)

    Go语言学习笔记十一: 切片(slice) 切片这个概念我是从python语言中学到的,当时感觉这个东西真的比较好用.不像java语言写起来就比较繁琐.不过我觉得未来java语法也会支持的. 定义切片 ...

随机推荐

  1. 解决redis连接错误:MISCONF Redis is configured to save RDB snapshots, but it is currently not able to...

    今天Redis服务器在连接redis数据库时突然报错:MISCONF Redis is configured to save RDB snapshots, but it is currently no ...

  2. JAVA 8 主要新特性 ----------------(七)新时间日期 API -----Instant 时间戳

    一.简介 用于“时间戳”的运算.它是以Unix元年(传统 的设定为UTC时区1970年1月1日午夜时分)开始 所经历的描述进行运算 二.文档介绍 1.now Instant instantNow = ...

  3. Linux二进制分析PDF

    链接:https://pan.baidu.com/s/1lp5mz30J3RamFyQIXRvx5w 提取码:vcdq 我就是看不惯csdn的付费下载,链接失效了就评论区留言,我能收到邮件.

  4. gitlab 之 项目管理

    首先git是什么? Git是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目.Git的读音为/gɪt/. Git是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常 ...

  5. GC调优

    Gc调优的目标:1.降低停顿时间 2.提高吞吐量 3.避免full-gc 调优可以使用的手段:1.各个内存区的大小调整:堆,年轻代,老年代,方法区等等2.减少短暂对象的存活时间,提高长期对象的复用率( ...

  6. Python机器学习步骤

    推荐学习顺序 学习机器学习得有个步骤, 下面大家就能按照自己所需, 来探索这个网站. 图中请找到 "Start", 然后依次沿着箭头, 看看有没有不了解/没学过的地方, 接着, 就 ...

  7. ORACLE知识点总结

    一.ORACEL常用命令 1.解锁账户:ALTER USER username ACCOUNT UNLOCK; 2.查看数据库字符集:SELECT USERENV ('language') FROM ...

  8. Python基础理论 - 常用模块

    time模块:时间戳.时间字符串.时间对象以及如何转换 random模块:随机小数.整数.区间,随机列表元素,打散列表 os模块:与操作系统交互的一个接口,os.path操作文件的路径 sys模块:s ...

  9. chat.css

    *, *:before, *:after { box-sizing: border-box;}body, html { height: 100%; overflow: hidden;}body, ul ...

  10. TDD:什么是桩(stub)和模拟(mock)?

    背景 本文假设你对TDD.Stub和Mock已经有了初步的认识,本文简单解释一下stub和mock的区别和使用场景,先看看他们之间的关系: 由上图可以知道mock框架可以非常容易的开发stub和moc ...