上篇链接: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. # 2019-2020-4 《Java 程序设计》第六周总结

    2019-2020-4 <Java 程序设计>第六周知识总结 第七章:内部类与异常类 1.内部类 (1)类可以有两种重要的成员:成员变量和方法,类还可以有一种成员:内部类. (2)java ...

  2. 绑定hover事件

    <label> <span id="pattern">实战模式</span> <div class='tab' style="t ...

  3. oracle BLOG图片和CLOG base64码的转换

    --BASE64转图片CREATE OR REPLACE FUNCTION DECODE_BASE64(P_CLOB_IN IN CLOB) RETURN BLOB IS V_BLOB BLOB; V ...

  4. 使用Python脚本分析你的网站上的SEO元素

    撰稿马尼克斯德芒克 上2019年1月, Sooda internetbureau Python就是自动执行重复性任务,为您的其他搜索引擎优化(SEO)工作留出更多时间.没有多少SEO使用Python来 ...

  5. 学习Acegi应用到实际项目中(11)- 切换用户

    在某些应用场合中,可能需要用到切换用户的功能,从而以另一用户的身份进行相关操作.这一点类似于在Linux系统中,用su命令切换到另一用户进行相关操作. 既然实际应用中有这种场合,那么我们就有必要对其进 ...

  6. 2019.03.09 codeforces620E. New Year Tree(线段树+状态压缩)

    传送门 题意:给一棵带颜色的树,可以给子树染色或者问子树里有几种不同的颜色,颜色值不超过606060. 思路:颜色值很小,因此状压一个区间里的颜色用线段树取并集即可. 代码: #include< ...

  7. shell编写自动化安装dhcp服务

    #!/bin/bash#Auth:Darius#自动化安装dhcp服务#"$1"为测试IP,用来查看IP段是否能通eno=`ifconfig|awk '{print $1}'|he ...

  8. ubuntu installs matlab2017a

    cd mkdir matlab sudo mount -o loop *1.iso matlab sudo ./matlab/install ... sudo mount -o loop *2.iso ...

  9. ASCII、Unicode、UTF-8以及Python3编码问题

    编码问题,其实的确是个很烦人的问题,一开始觉得不需要看,到后来出现问题,真的是抓狂, 而像我们这些刚刚涉及到这些问题的小白来说,更是无从下手,所以查阅资料,总结理解下各个概念以及Python3的编码问 ...

  10. hive 函数 nvl()

    首先用desc function,查看hive给出的函数解释 nvl(value,default_value) - Returns default value if value is null els ...