zoukankan      html  css  js  c++  java
  • 【EF6学习笔记】(十一)实施继承

    上篇链接: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(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:
    最后看看数据库的结果:

    最后数据库的结构变为:

  • 相关阅读:
    iOS 中使用 XIB 自定义cell的两种方法以及编译出现常见 的错误 (xcode6.0之后)
    iOS中 学会如何对sqlite3 进行封装
    杭电ACM2012素数判定
    杭电ACM2503a/b+c/d
    杭电ACM2005第几天
    杭电ACM2034人见人爱AB
    杭电ACM2502月之数
    杭电ACM2001计算两点间的距离
    杭电ACM2002计算求得体积
    杭电ACM2033人见人爱A+B
  • 原文地址:https://www.cnblogs.com/wyt007/p/8488868.html
Copyright © 2011-2022 走看看