TPH-Vererbung im Designer

In dieser exemplarischen Vorgehensweise wird Schritt für Schritt gezeigt, wie Sie die TPH-Vererbung (Tabelle pro Hierarchie) mithilfe des Entity Framework-Designers (EF Designer) in Ihr konzeptionelles Modell implementieren. Die TPH-Vererbung verwendet eine Datenbanktabelle, um die Daten aller Entitätstypen in einer Vererbungshierarchie zu verwalten.

In dieser exemplarischen Vorgehensweise ordnen wir die Tabelle „Person“ drei Entitätstypen zu: Person (Basistyp), Student (abgeleitet von „Person“) und Instructor (abgeleitet von „Person“). Wir erstellen ein konzeptionelles Modell aus der Datenbank (Database First) und ändern dann das Modell, um die TPH-Vererbung mithilfe von EF Designer zu implementieren.

Es ist möglich, eine TPH-Vererbung mithilfe von Model First zuzuordnen, aber Sie müssten Ihren eigenen Workflow zur Datenbankgenerierung schreiben, was komplex ist. Anschließend weisen Sie diesen Workflow der Eigenschaft Workflow zur Datenbankgenerierung in EF Designer zu. Eine einfachere Alternative ist die Verwendung von Code First.

Weitere Vererbungsoptionen

TPT (Tabelle pro Typ) ist eine weitere Vererbungsoption, bei der separate Tabellen in der Datenbank Entitäten zugeordnet werden, die an der Vererbung beteiligt sind.  Informationen zum Zuordnen der TPT-Vererbung mit EF Designer finden Sie unter TPT-Vererbung in EF Designer.

Die TP-Vererbung (Tabelle pro konkretem Typ) und gemischte Vererbungsmodelle werden von der Entity Framework-Runtime unterstützt, aber nicht von EF Designer. Wenn Sie TPC oder gemischte Vererbung verwenden möchten, haben Sie zwei Optionen: Verwenden Sie Code First, oder bearbeiten Sie die EDMX-Datei manuell. Wenn Sie sich für die Arbeit mit der EDMX-Datei entscheiden, wird das Fenster „Zuordnungsdetails“ in den abgesicherten Modus versetzt, und Sie können den Designer nicht verwenden, um die Zuordnungen zu ändern.

Voraussetzungen

Für diese exemplarische Vorgehensweise gelten folgende Voraussetzungen:

  • Eine aktuelle Version von Visual Studio
  • Die Beispieldatenbank School

Einrichten des Projekts

  • Öffnen Sie Visual Studio 2012.
  • Wählen Sie Datei > Neu > Projekt aus.
  • Klicken Sie im linken Bereich auf Visual C#, und wählen Sie dann die Konsolenvorlage aus.
  • Geben Sie TPHDBFirstSample als Namen ein.
  • Klicken Sie auf OK.

Modellerstellung

  • Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Projektnamen, und wählen Sie Hinzufügen > Neues Element aus.
  • Wählen Sie Daten im linken Menü aus, und wählen Sie dann im Bereich „Vorlagen“ ADO.NET Entity Data Model aus.
  • Geben Sie TPHModel.edmx für den Dateinamen ein, und klicken Sie dann auf Hinzufügen.
  • Wählen Sie im Dialogfeld „Modellinhalt auswählen“ Aus Datenbank generieren aus, und klicken Sie dann auf Weiter.
  • Klicken Sie auf Neue Verbindung. Geben Sie im Dialogfeld „Verbindungseigenschaften“ den Servernamen ein (z. B. (localdb)\mssqllocaldb), wählen Sie die Authentifizierungsmethode aus, geben Sie School als Datenbanknamen ein, und klicken Sie dann auf OK. Das Dialogfeld „Datenverbindung auswählen“ wird mit Ihrer Datenbankverbindungseinstellung aktualisiert.
  • Wählen Sie im Dialogfeld „Datenbankobjekte auswählen“ unter dem Knoten „Tabellen“ die Tabelle Person aus.
  • Klicken Sie auf Fertig stellen.

Der Entity Designer, der eine Entwurfsoberfläche zum Bearbeiten Ihres Modells bereitstellt, wird angezeigt. Alle Objekte, die Sie im Dialogfeld „Datenbankobjekte auswählen“ ausgewählt haben, werden dem Modell hinzugefügt.

So sieht die Tabelle Person in der Datenbank aus.

Person Table 

Implementieren der TPH-Vererbung

Die Tabelle Person enthält die Spalte Discriminator, die einen von zwei Werten aufweisen kann: „Student“ oder „Instructor“. Je nach Wert wird die Tabelle Person der Entität Student oder der Entität Instructor zugeordnet. Die Tabelle Person enthält auch zwei Spalten, HireDate und EnrollmentDate, die Nullwerte zulassen müssen, da eine Person nicht gleichzeitig am Unterricht teilnehmen und diesen leiten kann (zumindest nicht in dieser exemplarischen Vorgehensweise).

Hinzufügen neuer Entitäten

  • Fügen Sie eine neue Entität hinzu. Klicken Sie hierfür mit der rechten Maustaste auf einen leeren Bereich der Entwurfsoberfläche des Entity Framework-Designers, und wählen Sie Hinzufügen > Entität aus.
  • Geben Sie Instructor als Entitätsnamen ein, und wählen Sie in der Dropdownliste Person als Basistyp aus.
  • Klicken Sie auf OK.
  • Fügen Sie eine weitere neue Entität hinzu. Geben Sie Student als Entitätsnamen ein, und wählen Sie in der Dropdownliste Person als Basistyp aus.

Der Entwurfsoberfläche wurden zwei neue Entitätstypen hinzugefügt. Ein Pfeil zeigt von den neuen Entitätstypen auf den Entitätstyp Person. Das bedeutet, dass Person der Basistyp für die neuen Entitätstypen ist.

  • Klicken Sie mit der rechten Maustaste auf die Eigenschaft HireDate der Entität Person. Wählen Sie Ausschneiden aus, oder verwenden Sie die Tastenkombination STRG+X.
  • Klicken Sie mit der rechten Maustaste auf die Entität Instructor, und wählen Sie Einfügen aus, oder verwenden Sie die Tastenkombination STRG+V.
  • Klicken Sie mit der rechten Maustaste auf die Eigenschaft HireDate, und wählen Sie Eigenschaften aus.
  • Legen Sie im Fenster Eigenschaften die Eigenschaft Nullwerte zulassend auf false fest.
  • Klicken Sie mit der rechten Maustaste auf die Eigenschaft EnrollmentDate der Entität Person. Wählen Sie Ausschneiden aus, oder verwenden Sie die Tastenkombination STRG+X.
  • Klicken Sie mit der rechten Maustaste auf die Entität Student, und wählen Sie Einfügen aus, oder verwenden Sie die Tastenkombination STRG+V.
  • Wählen Sie die Eigenschaft EnrollmentDate aus, und legen Sie die Eigenschaft Nullwerte zulassend auf false fest.
  • Wählen Sie den Entitätstyp Person aus. Legen Sie im Fenster Eigenschaften die Eigenschaft Abstrakt auf true fest.
  • Löschen Sie die Eigenschaft Discriminator aus Person. Der Grund, warum diese gelöscht werden soll, wird im folgenden Abschnitt erläutert.

Zuordnen der Entitäten

  • Klicken Sie mit der rechten Maustaste auf Instructor, und wählen Sie Tabellenzuordnung aus. Die Entität „Instructor“ ist im Fenster „Zuordnungsdetails“ ausgewählt.

  • Klicken Sie im Fenster Zuordnungsdetails auf <Tabelle oder Sicht hinzufügen>. Das Feld <Tabelle oder Sicht hinzufügen> wird zu einer Dropdownliste der Tabellen oder Sichten, denen die ausgewählte Entität zugeordnet werden kann.

  • Wählen Sie Person aus der Dropdownliste aus.

  • Das Fenster Zuordnungsdetails wird mit Standardspaltenzuordnungen und einer Option zum Hinzufügen einer Bedingung aktualisiert.

  • Klicken Sie auf <Bedingung hinzufügen>. Das Feld <Bedingung hinzufügen> wird zu einer Dropdownliste mit Spalten, für die Bedingungen festgelegt werden können.

  • Wählen Sie Discriminator aus der Dropdownliste aus.

  • Wählen Sie in der Spalte Operator des Fensters Zuordnungsdetails „=“ aus der Dropdownliste aus.

  • Geben Sie in der Spalte Wert/EigenschaftInstructor ein. Das Endergebnis sollte wie folgt aussehen:

    Mapping Details

  • Wiederholen Sie diese Schritte für den Entitätstyp Student, aber legen Sie die Bedingung so fest, dass dem Wert Student genau entsprochen werden muss.
    Der Grund, warum die Eigenschaft Discriminator Eigenschaft werden sollte, liegt darin, dass Sie eine Tabellenspalte nicht mehr als einmal zuordnen können. Diese Spalte wird für die bedingte Zuordnung verwendet, sodass sie nicht auch für die Eigenschaftszuordnung verwendet werden kann. Die einzige Möglichkeit, wie sie für beides verwendet werden kann, besteht darin, eine Bedingung mit einem Ist NULL- oder Ist nicht NULL-Vergleich zu verwenden.

Die "Tabelle pro Hierarchie"-Vererbung ist jetzt implementiert.

Final TPH

Verwenden des Modells

Öffnen Sie die Datei Program.cs, in der die Methode Main definiert ist. Fügen Sie der Funktion Main den folgenden Code hinzu. Der Code führt drei Abfragen aus. Die erste Abfrage gibt alle Person-Objekte zurück. Die zweite Abfrage verwendet die OfType-Methode, um Instructor-Objekte zurückzugeben. Die dritte Abfrage verwendet die OfType-Methode, um Student-Objekte zurückzugeben.

    using (var context = new SchoolEntities())
    {
        Console.WriteLine("All people:");
        foreach (var person in context.People)
        {
            Console.WriteLine("    {0} {1}", person.FirstName, person.LastName);
        }

        Console.WriteLine("Instructors only: ");
        foreach (var person in context.People.OfType<Instructor>())
        {
            Console.WriteLine("    {0} {1}", person.FirstName, person.LastName);
        }

        Console.WriteLine("Students only: ");
        foreach (var person in context.People.OfType<Student>())
        {
            Console.WriteLine("    {0} {1}", person.FirstName, person.LastName);
        }
    }