Translation: Getting Started with Entity Framework 6 of MVC5 (11)-Implementing inheritance for ASP.NET MVC applications

Implement inheritance for ASP.NET MVC applications

This is a translation of Microsoft's official tutorial Getting Started with Entity Framework 6 Code First using MVC 5 series, here is the eleventh article: Implementing inheritance for ASP.NET MVC applications

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


In the previous tutorial, you have learned how to handle concurrent exceptions. In this tutorial, we will introduce how to implement inheritance.

In object-oriented programming, you can use inheritance to reuse code. In this tutorial, you will change the Instructor and Student classes so that they are derived from the Person base class that contains the name attribute. You don't need to change any WEB pages, but your changes will be automatically reflected in the database.

Mapping options inherited to the database

The Instructor and Student classes in the data model have several identical properties:

models

Suppose you want to eliminate redundant code by sharing the attributes of the teacher and student entities, or you want to write a service that does not care whether the name comes from the student or teacher to format the name correctly. You can create a Person base class that contains these shared attributes, and then make the classes of the teacher and student entities inherit from the base class, as shown in the following figure:

models

In the database, this inheritance structure has several manifestations. You can create a Person data table, a single table containing teacher and student and student information, some columns may only apply to teachers (date of employment), some only apply to students (date of registration), and some both (Surname, first name). Usually, you will have an identification column to indicate the type represented by each row. For example, the identification column may use "Instructor" to indicate a teacher and "Student" to indicate a student.

table

The mode of generating an entity inheritance structure from a single database table is called a table inheritance mode per layer.

The alternative is to use a database that looks more like an inheritance structure. For example, you can only include attributes common to students and teachers in the Person table, and place unique attributes in separate tables.

tables

Make each entity class establish a database table mode becomes a table inheritance for each type.

But another option is to map all non-abstract types to a single table. All categories of attributes, including inherited ones, will be mapped to columns in the corresponding table. This pattern is called one-table inheritance per concrete class. If you implement the table inheritance of the specific classes of the Person, Student and Instructor classes, the Student and Instructor data tables will be the same as what you have seen before.

One table per concrete class and one table per layer in the Entity Framework will usually provide better performance than one table per type, because one table per type may result in complex join queries.

This tutorial will demonstrate how to implement one table inheritance per layer. One table per layer is the default inheritance mode of Entity Framework. All you have to do is create a Person class, modify the Instructor and Student classes derived from Person, add the new class to DbContext and create the migration.

Create Person class

In the Models folder, use the following code to create the Person class:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.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;
            }
        }
    }
}

Make the Student and Instructor classes inherit from Person

In the Instructor class, modify the class derived from Person and delete the name field, as in the following code:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.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; }
    }
}

Also modify the Student class:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.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; }
    }
}

Add Person entity type to the model

Add a Person entity DbSet property to SchoolContext.cs:

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

It is to implement all modifications needed to implement inheritance in the Entity Framework. Later you will see that after the database is updated, there will be a new Person data table.

Create and update a migration file

In the package manager console, enter the following command:

Add-Migration Inheritance

After running the update-database command, the command will fail. Because the Entity Framework does not know how to migrate our existing data, the error message is similar to the following:

Could not drop object ‘dbo.Instructor’ because it is referenced by a FOREIGN KEY constraint.

Open Migrations \ <Timestamp> -Inheritance.cs file and replace the Up method with the following code:

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, defaultValue: "Instructor"));
    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");
}

This code performs the following database update tasks:

  • Removed foreign key constraints and indexes pointing to student data table

  • Renamed Instructor table to Person table and modified it:

    • Added an empty EnrollmentDate for students
    • Added an identification column to indicate whether the row is a student or teacher
    • Make the employment date blank, because the student ’s trip will not have an employment date
    • Add a temporary field to update the foreign key to the student. When you copy students back to the Person table, they will have a new primary key value.
  • Copy the data from the student table to the Person table, which causes the student to have a new primary key value

  • Fixed foreign key values ​​pointing to students

  • Recreate foreign key constraints and indexes, now they point to the Person table

(If you use GUID instead of int as the primary key type, the student's primary key value will not change, the above steps may be omitted.)

Run the update-database command again.

Note : You can still get an error. During the migration or architecture change, if the migration error cannot be resolved, you can continue this tutorial by changing the web.config connection string or deleting the database. The easiest way is Rename the database.

test

Run the application, try various operations, everything runs normally.

In the Server Explorer, expand the data connection, expand the SchoolContext data table, you will see that the Person table has replaced the Student and Instructor tables, open the Person table, you will see the previous student and teacher information.

Server Explorer

dbo.Person

The following diagram illustrates the structure of the new database:

models

Deploy to Windows Azure

slightly…

to sum up

You now implement table inheritance at each level of the Person, Student, and Instructor classes. For information on other inheritance structures, see TPH Inheritance Pattern and TPT Inheritance Pattern . In the next tutorial, you will see how to implement warehousing and unit working modes.

author information

tom-dykstra Tom Dykstra -Tom Dykstra is a senior programmer and writer on the Microsoft Web Platform and Tools team.

Published 40 original articles · 25 praises · 100,000+ views

Guess you like

Origin blog.csdn.net/yym373872996/article/details/69487757