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:
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:
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.
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.
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 Person
abzuleiten, die neue Klasse zu hinzufügen und eine Migration zu DbContext
erstellen. (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:
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.
Klicken Sie im Projektmappen-Explorer von Visual Studio mit der rechten Maustaste auf das Projekt, und wählen Sie im Kontextmenü Veröffentlichen aus.
Klicken Sie auf Veröffentlichen.
Die Web-App wird in Ihrem Standardbrowser geöffnet.
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.