EF學習筆記(十一):實施繼承

學習總目錄:ASP.NET MVC5 及 EF6 學習筆記 - (目錄整理)html

上篇連接:EF學習筆記(十) 處理併發數據庫

本篇原文連接:Implementing Inheritance併發

面向對象的世界裏,繼承能夠很好的重用代碼。在本章就對Instructor和Student兩個類進行實施繼承處理,這兩個類有公用的屬性,好比LastName等,也有私有的屬性;mvc

能夠不用增長任何頁面,進行修改一些代碼,這些修改後的繼承關係就會自動反應到數據庫中。app

經過下圖能夠看到兩個類有哪些公用屬性:ide

那麼就能夠建一個Person的基礎類,讓這兩個類繼承自Persion類:性能

 

Options for mapping inheritance to database tables學習

映射繼承到數據庫表有如下3種方式:ui

TPH: table-per-hierarchyspa

在數據庫裏就建一個表,裏面除了有公有的字段外,既有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(50)]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }
        [Required]
        [StringLength(50, 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: 128));
            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:
最後看看數據庫的結果:

最後數據庫的結構變爲:

相關文章
相關標籤/搜索