Tutorial: Implementieren der Vererbung mit EF in einer ASP.NET MVC 5-App

Im vorherigen Tutorial haben Sie Parallelitätsausnahmen behandelt. In diesem Tutorial erfahren Sie, wie Sie die Vererbung in das Datenmodell implementieren können.

Bei der objektorientierten Programmierung können Sie die Vererbung verwenden, um die Wiederverwendung von Code zu erleichtern. In diesem Tutorial ändern Sie die Klassen Instructor und Student so, dass sie von einer Person-Basisklasse abgeleitet werden, die Eigenschaften wie LastName enthält. Diese Eigenschaften sind für Dozenten und Studenten gängig. Sie fügen keine Webseiten hinzu oder ändern diese, aber Sie werden Teile des Codes ändern. Diese Änderungen werden automatisch in der Datenbank widergespiegelt.

In diesem Tutorial:

  • Informationen zum Zuordnen der Vererbung zur Datenbank
  • Erstellen der Klasse „Person“
  • Aktualisieren von „Instructor“ und „Student“
  • Hinzufügen einer Person zum Modell
  • Erstellen und Aktualisieren von Migrationen
  • Testen der Implementierung
  • In Azure bereitstellen

Voraussetzungen

Zuordnen von Vererbung zu Datenbank

Die Instructor Klassen und Student im School Datenmodell verfügen über mehrere Eigenschaften, die identisch sind:

Student_and_Instructor_classes

Angenommen, Sie möchten den redundanten Code für die Eigenschaften löschen, die von den Entitäten Instructor und Student gemeinsam genutzt werden. Oder Sie möchten einen Dienst schreiben, mit dem Namen formatiert werden können, ohne dass es eine Rolle spielt, ob der Name von einem Dozenten oder von einem Studenten stammt. Sie können eine Person Basisklasse erstellen, die nur diese freigegebenen Eigenschaften enthält, und dann die Instructor Entitäten und Student von dieser Basisklasse erben lassen, wie in der folgenden Abbildung gezeigt:

Student_and_Instructor_classes_deriving_from_Person_class

Es gibt mehrere Möglichkeiten, wie diese Vererbungsstruktur in der Datenbank dargestellt werden kann. Beispielsweise könnte die Tabelle Person vorhanden sein, die Informationen zu Studierenden und Lehrkräften in einer einzigen Tabelle enthält. Einige der Spalten können nur für Kursleiter (HireDate), andere nur für Kursteilnehmer (EnrollmentDate), andere für beide (LastName, FirstName) gelten. In der Regel verfügen Sie über eine Diskriminatorspalte , um anzugeben, welchen Typ jede Zeile darstellt. So kann die Unterscheidungsspalte beispielsweise „Instructor“ für Dozenten und „Student“ für Studenten enthalten.

Tabelle pro hierarchy_example

Dieses Muster zum Generieren einer Entitätsvererbungsstruktur aus einer einzelnen Datenbanktabelle wird als TPH-Vererbung (Table-per-hierarchy ) bezeichnet.

Alternativ kann die Datenbank so gestaltet werden, dass sie mehr wie die Vererbungsstruktur aussieht. Die Tabelle Person könnte beispielsweise nur die Namensfelder aufweisen, während die Datumsfelder in den separaten Tabellen Instructor und Student vorhanden sind.

Tabelle pro type_inheritance

Dieses Muster zum Erstellen einer Datenbanktabelle für jede Entitätsklasse wird als TPT-Vererbung ( Table per Type ) bezeichnet.

Eine weitere Möglichkeit besteht darin, individuellen Tabellen alle nicht abstrakten Typen zuzuordnen. Alle Eigenschaften einer Klasse, einschließlich der geerbten Eigenschaften, werden Spalten der entsprechenden Tabelle zugeordnet. Dieses Muster wird als TPC-Vererbung (TPC = Table per Concrete, Tabelle pro konkretem Typ) bezeichnet. Wenn Sie die TPC-Vererbung für die Klassen Person, Student und Instructor wie oben beschrieben implementieren, würden die Tabellen Student und Instructor nach der Implementierung unverändert aussehen.

TPC- und TPH-Vererbungsmuster bieten im Entity Framework im Allgemeinen eine bessere Leistung als TPT-Vererbungsmuster, da TPT-Muster zu komplexen Joinabfragen führen können.

Dieses Tutorial veranschaulicht die Implementierung der TPH-Vererbung. TPH ist das Standardvererbungsmuster im Entity Framework. Sie müssen also nur eine Person Klasse erstellen, die Instructor Klassen und Student ändern, um von Personabzuleiten, die neue Klasse zu hinzufügen und eine Migration zu DbContexterstellen. (Informationen zum Implementieren der anderen Vererbungsmuster finden Sie unter Zuordnen der TpT-Vererbung (Table-Per-Type) und Mapping the Table-Per-Concrete Class (TPC)-Vererbung in der MSDN Entity Framework-Dokumentation.)

Erstellen der Klasse „Person“

Erstellen Sie im Ordner ModelsPerson.cs , und ersetzen Sie den Vorlagencode durch den folgenden Code:

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;
            }
        }
    }
}

Aktualisieren von „Instructor“ und „Student“

Aktualisieren Sie nun Instructor.cs und Student.cs , um Werte vom Person.sc zu erben.

Leiten Sie in Instructor.cs die Instructor Klasse von der Person Klasse ab, und entfernen Sie die Felder Schlüssel und Name. Der Code sieht aus wie im folgenden Beispiel:

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; }
    }
}

Nehmen Sie ähnliche Änderungen an Student.cs vor. Die Student Klasse sieht wie im folgenden Beispiel aus:

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; }
    }
}

Hinzufügen einer Person zum Modell

Fügen Sie in SchoolContext.cs eine DbSet Eigenschaft für den Entitätstyp Person hinzu:

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

Das ist alles, was Entity Framework für die Konfiguration der „Tabelle pro Hierarchie“-Vererbung benötigt. Wie Sie sehen werden, enthält die Datenbank, wenn sie aktualisiert wird, eine Person Tabelle anstelle der Student Tabellen und Instructor .

Erstellen und Aktualisieren von Migrationen

Geben Sie in der Paket-Manager-Konsole (PMC) den folgenden Befehl ein:

Add-Migration Inheritance

Führen Sie den Update-Database Befehl im PMC aus. Der Befehl schlägt an diesem Punkt fehl, da wir über vorhandene Daten verfügen, die von Migrationen nicht zu behandeln sind. Sie erhalten eine Fehlermeldung wie die folgende:

Objekt 'dbo konnte nicht gelöscht werden. Kursleiter, da von einer FOREIGN KEY-Einschränkung darauf verwiesen wird.

Migrationen< timestamp>_Inheritance.cs, und ersetzen Sie die Up -Methode durch den folgenden 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");
}

Dieser Code übernimmt folgende Tasks für Datenbankaktualisierungen:

  • Er entfernt Fremdschlüsseleinschränkungen und -indizes, die auf die Tabelle „Student“ verweisen.

  • Er benennt die Tabelle „Instructor“ in „Person“ um und nimmt die Änderungen vor, die für das Speichern von Studentendaten erforderlich sind:

    • Er fügt das EnrollmentDate für Studenten hinzu, bei dem NULL-Werte zugelassen sind.
    • Er fügt eine Unterscheidungsspalte hinzu, um anzugeben, ob eine Zeile für einen Studenten oder für einen Dozenten bestimmt ist.
    • Er legt fest, dass bei HireDate NULL-Werte zugelassen sind, da die Zeilen für Studenten keine Einstellungsdaten enthalten.
    • Er fügt ein temporäres Feld hinzu, über das Fremdschlüssel aktualisiert werden sollen, die auf Studenten verweisen. Wenn Sie Kursteilnehmer in die Tabelle Person kopieren, erhalten sie neue Primärschlüsselwerte.
  • Kopiert Daten aus der Tabelle „Student“ in die Tabelle „Person“. Dadurch werden Studenten neue Primärschlüsselwerte zugewiesen.

  • Er legt Fremdschlüsselwerte fest, die auf Studenten verweisen.

  • Er erstellt Fremdschlüsseleinschränkungen und -indizes neu, die dann auf die Tabelle „Person“ verweisen.

(Hätten Sie als Primärschlüsseltyp statt einem Integer die grafische Benutzeroberfläche verwendet haben, hätten die Primärschlüsselwerte für Studenten nicht geändert werden müssen, und mehrere dieser Schritte hätten ausgelassen werden können.)

Führen Sie den Befehl update-database erneut aus.

(In einem Produktionssystem würden Sie entsprechende Änderungen an der Down-Methode vornehmen, falls Sie diese jemals verwenden mussten, um zur vorherigen Datenbankversion zurückzukehren. Für dieses Tutorial verwenden Sie nicht die Down-Methode.)

Hinweis

Es ist möglich, andere Fehler beim Migrieren von Daten und beim Vornehmen von Schemaänderungen zu erhalten. Wenn Sie Migrationsfehler erhalten, die Sie nicht beheben können, können Sie mit dem Tutorial fortfahren, indem Sie die Verbindungszeichenfolge in der Web.config-Datei ändern oder die Datenbank löschen. Der einfachste Ansatz besteht darin, die Datenbank in der Web.config-Datei umzubenennen. Ändern Sie beispielsweise den Datenbanknamen in ContosoUniversity2, wie im folgenden Beispiel gezeigt:

<add name="SchoolContext" 
    connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=ContosoUniversity2;Integrated Security=SSPI;" 
    providerName="System.Data.SqlClient" />

Bei einer neuen Datenbank sind keine Daten zu migrieren, und der update-database Befehl wird viel wahrscheinlicher ohne Fehler ausgeführt. Anweisungen zum Löschen der Datenbank finden Sie unter Löschen einer Datenbank aus Visual Studio 2012. Wenn Sie diesen Ansatz verwenden, um mit dem Tutorial fortzufahren, überspringen Sie den Bereitstellungsschritt am Ende dieses Tutorials, oder stellen Sie die Bereitstellung auf einer neuen Website und Datenbank bereit. Wenn Sie ein Update auf demselben Standort bereitstellen, auf dem Sie bereits bereitgestellt haben, erhält EF denselben Fehler, wenn Migrationen automatisch ausgeführt werden. Wenn Sie einen Migrationsfehler beheben möchten, ist die beste Ressource eines der Entity Framework-Foren oder StackOverflow.com.

Testen der Implementierung

Führen Sie die Website aus, und probieren Sie verschiedene Seiten aus. Alles funktioniert genauso wie vorher.

Erweitern Sie in Server ExplorerDatenverbindungen\SchoolContext und dann Tabellen, und Sie sehen, dass die Tabellen Student und Instructor durch eine Person-Tabelle ersetzt wurden. Erweitern Sie die Tabelle Person , und Sie sehen, dass sie alle Spalten enthält, die sich früher in den Tabellen Student und Instructor befinden.

Klicken Sie mit der rechten Maustaste auf die Tabelle „Person“, und klicken Sie anschließend auf Tabellendaten anzeigen, um die Unterscheidungsspalte anzuzeigen.

Das folgende Diagramm veranschaulicht die Struktur der neuen School-Datenbank:

School_database_diagram

In Azure bereitstellen

In diesem Abschnitt müssen Sie den optionalen Abschnitt Bereitstellen der App in Azure in Teil 3, Sortieren, Filtern und Paging dieser Tutorialreihe abgeschlossen haben. Wenn Migrationsfehler aufgetreten sind, die Sie durch löschen der Datenbank in Ihrem lokalen Projekt behoben haben, überspringen Sie diesen Schritt. oder erstellen Sie einen neuen Standort und eine neue Datenbank, und stellen Sie sie in der neuen Umgebung bereit.

  1. Klicken Sie im Projektmappen-Explorer von Visual Studio mit der rechten Maustaste auf das Projekt, und wählen Sie im Kontextmenü Veröffentlichen aus.

  2. Klicken Sie auf Veröffentlichen.

    Die Web-App wird in Ihrem Standardbrowser geöffnet.

  3. Testen Sie die Anwendung, um zu überprüfen, ob sie funktioniert.

    Wenn Sie zum ersten Mal eine Seite ausführen, die auf die Datenbank zugreift, führt Entity Framework alle Migrationsmethoden Up aus, die erforderlich sind, um die Datenbank mit dem aktuellen Datenmodell auf den neuesten Stand zu bringen.

Abrufen des Codes

Abgeschlossenes Projekt herunterladen

Zusätzliche Ressourcen

Links zu anderen Entity Framework-Ressourcen finden Sie im ASP.NET Datenzugriff – Empfohlene Ressourcen.

Weitere Informationen zu dieser und anderen Vererbungsstrukturen finden Sie unter TPT-Vererbungsmuster und TPH-Vererbungsmuster auf MSDN. Im nächsten Tutorial erfahren Sie, wie Sie eine Vielzahl von Entity Framework-Szenarios auf fortgeschrittenem Niveau verarbeiten können.

Nächste Schritte

In diesem Tutorial:

  • Informationen zum Zuordnen der Vererbung zur Datenbank
  • Klasse „Person“ wurde erstellt
  • „Instructor“ und „Student“ wurden aktualisiert
  • Person zum Modell hinzugefügt
  • Migrationen erstellt und aktualisiert
  • Die Implementierung wurde getestet
  • Bereitgestellt in Azure

Fahren Sie mit dem nächsten Artikel fort, um mehr über Themen zu erfahren, die hilfreich sind, wenn Sie über die Grundlagen der Entwicklung von ASP.NET Webanwendungen hinausgehen, die Entity Framework Code First verwenden.