Fork me on GitHub

MVC5 Entity Framework学习(11):实现继承

之前你已经学习了如何处理并发异常,在本节中你将学习如何实现继承。

在面向对象的编程中,你可以使用继承来重用代码。接下来你将修改Instructor和Student类,让它们派生自Person基类,该基类包含instructor和student共有的属性如LastName。你不需要添加或修改任何WEB页面,但是你需要修改某些代码,这些修改会自动反映在数据库中。

映射继承到数据库的选项

School 数据模型中的Instructor和Student类有几个相同的属性:

20140923211021906

假设你希望通过共享Instructor和Student实体的属性来减少冗余的代码,或者你希望编写一个服务程序来格式化姓名而不必关心姓名来自instructor还是student。你可以创建一个含有这些共有属性的Person基类,然后让Instructor和Student继承该基类,如下图所示:

20140923220914109

在数据库中,这种继承结构可以有多种表现形式。你可以创建一个同时含有student和instructor信息的Person数据库表,该表中的某些列仅适用于instructor(HireDate),某些只适用于student(EnrollmentDate),另外的即可适用于instructor也可适用于student(LastName, FirstName)。通常情况下,你应该创建一个标识列来指明每一行所代表的类型,例如,标识列可以使用”Instructor”来表示instructors ,”Student”来表示students。

20140923222146683

这种从单个数据库表生成实体继承结构的模式被称为每个层次结构一个表(table-per-hierarchy)继承。

另一种替代方法是使数据库看起来更像是继承结构,,例如,你可以只在Person表中包含name字段,在Instructor 和Student表中分别包含各自的date字段。

20140923223038718

这种为每个实体类都建立一个数据库表的模式被称为每种类型一个表(table per type)继承。

另一种选择是将所有非抽象类型映射到单独的表中。类的所有属性包括继承的,都将映射到相应表中的列,这种模式被称为每个具体的类一个表(Table-per-Concrete Class )继承。如果你为Person,Student和Instructor类实现了TPC 继承,那么Student和Instructor表将与之前的没有什么不同。

在Entity Framework中TPC 和TPH继承模式通常比TPT继承模式具有更好地性能,因为TPT模式可能会产生复杂的连接查询。

本节将教你如何实现TPH继承。TPH继承是Entity Framework默认的继承模式,所以你需要做的就是创建一个Person类,修改Instructor和Student类使其派生自Person类,将新的类添加到DbContext,并创建迁移。

创建Person类

打开Models文件夹,新建Person.cs类,并使用下面的方法替换

让Student和Instructor类继承Person

打开Instructor.cs,让Instructor类继承Person类,并删除key 和name字段

打开Student.cs,做同样的修改

将Person实体类型添加到模型中

打开 SchoolContext.cs,为Person实体类型添加DbSet 属性

这就是 Entity Framework配置每个层次结构一个表继承所需要做的修改,稍后你会看到当数据库被更新后,会有一个新建的Person数据表。

创建并更新迁移文件

在 Package Manager Console (PMC)窗口,输入如下命令

接着运行Update-Database命令,这时该命令会执行失败,因为迁移程序不知道如何处理已经存在的数据。错误信息如下

打开Migrations\<timestamp>_Inheritance.cs,修改Up方法

上面的代码执行了下列数据库更新任务:

移除了Student数据库表的外键约束和索引

  • 将Instructor表重命名为Person并作如下修改来存储Student 数据
    • 为Student 添加了可以为nullable 的EnrollmentDate
    • 添加了标识列来指明该列是一个student 还是instructor
    • 由于student 没有hire date,所以设置HireDate可为nullable
    • 添加一个临时字段用来更新指向student 的外键
  • 将Student表中的数据拷贝到Person表中,这样Student可以得到一个新的主键值
  • 修复了指向student的外键值
  • 重建了外键约束和索引,让它们指向Person表

如果你已经使用了GUID而不是将integer作为主键类型,student 的主键值将不会被更改,同时上面的几个步骤可以被省略。

再次运行update-database命令。

在生产环境中你需要对Down方法进行相应的修改以免你不得不回滚至前一个数据库版本。在本例中不需要使用Down方法。

注意:当迁移数据或更改架构时,你可能会碰到其它的错误,如果你遇到了迁移错误却无法解决,你可以通过修改Web.config文件中的连接字符串或删除已存在的数据库的方法来继续本教程,当然最简单的方法是重新命名Web.config中的数据库。如下所示将数据库名称修改为ContosoUniversity2

通过使用新建的不存在任何数据的数据库来进行迁移,update-database应该会被成功执行。

测试

运行项目,尝试访问不同的页面,一切运行正常。

打开Server Explorer依次展开Data Connections\SchoolContext \Tables,你可以看到Student和Instructor表已经被Person表替换,打开Person表,你可以看到该表拥有 Student 和Instructor表的所有列。

20140925214722977

在Person表上右键单击Show Table Data查看discriminator列

20140925214735597

下面是新的School数据库架构

20140925214757656

部署到Windows Azure

1.在Visual Studio中,在Solution Explorer上右键选择Publish

20140924231443375

2.点击Publish

20140924231651770

默认浏览器中会自动打开该站点

3.验证应用程序会否工作正常

当你第一次运行项目并访问数据库时,Entity Framework会自动运行所有迁移中的Up方法来确保数据库架构和当前数据模型一致。

原文:Implementing Inheritance with the Entity Framework 6 in an ASP.NET MVC 5 Application

项目源码:https://github.com/johnsonz/MvcContosoUniversity

 

作者:Johnson
原创文章,版权所有,转载请保留原文链接。

发表评论

电子邮件地址不会被公开。 必填项已用*标注