Vererbung

EF kann einer Datenbank eine .NET-Typhierarchie zuordnen. Auf diese Weise können Sie Ihre .NET-Entitäten wie gewohnt in Code schreiben, basisbasierte und abgeleitete Typen verwenden und EF nahtlos das entsprechende Datenbankschema erstellen, Abfragen ausgeben usw. Die tatsächlichen Details zur Zuordnung einer Typhierarchie sind anbieterabhängig; Auf dieser Seite wird die Unterstützung der Vererbung im Kontext einer relationalen Datenbank beschrieben.

Zuordnung der Entitätstyphierarchie

Gemäß Konvention sucht EF nicht automatisch nach Basis- oder abgeleiteten Typen. Dies bedeutet, dass Sie diesen Typ explizit in Ihrem Modell angeben müssen, wenn Sie einen CLR-Typ in Ihrer Hierarchie zuordnen möchten. Beispielsweise führt die Angabe nur des Basistyps einer Hierarchie dazu, dass EF Core nicht implizit alle Untertypen einschließt.

Im folgenden Beispiel wird ein DbSet für Blog und seine Unterklasse RssBlogverfügbar gemacht. Wenn Blog eine andere Unterklasse vorhanden ist, wird sie nicht in das Modell einbezogen.

internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<RssBlog> RssBlogs { get; set; }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

public class RssBlog : Blog
{
    public string RssUrl { get; set; }
}

Hinweis

Datenbankspalten werden bei Verwendung der TPH-Zuordnung automatisch nullfähig gemacht. Beispielsweise kann die RssUrl Spalte NULL-Werte zulassen, da reguläre Blog Instanzen nicht über diese Eigenschaft verfügen.

Wenn Sie eine für eine oder mehrere Entitäten in der Hierarchie nicht verfügbar machen DbSet möchten, können Sie auch die Fluent-API verwenden, um sicherzustellen, dass sie in das Modell aufgenommen werden.

Tipp

Wenn Sie sich nicht auf Konventionen verlassen, können Sie den Basistyp explizit mit HasBaseTypeangeben. Sie können auch verwenden .HasBaseType((Type)null) , um einen Entitätstyp aus der Hierarchie zu entfernen.

Tabelle pro Hierarchie und Diskriminatorkonfiguration

Standardmäßig ordnet EF die Vererbung mit dem TPH-Muster (Table-per-hierarchy ) zu. TPH verwendet eine einzelne Tabelle, um die Daten für alle Typen in der Hierarchie zu speichern, und eine Diskriminatorspalte wird verwendet, um zu identifizieren, welchen Typ die einzelnen Zeilen darstellen.

Das obige Modell ist dem folgenden Datenbankschema zugeordnet (beachten Sie die implizit erstellte Discriminator Spalte, die angibt, welcher Typ von Blog in jeder Zeile gespeichert ist).

Screenshot der Ergebnisse der Abfrage der Blog-Entitätshierarchie mithilfe des Tabellen-pro-Hierarchie-Musters

Sie können den Namen und Den Typ der Diskriminatorspalte und die Werte konfigurieren, die zum Identifizieren der einzelnen Typen in der Hierarchie verwendet werden:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasDiscriminator<string>("blog_type")
        .HasValue<Blog>("blog_base")
        .HasValue<RssBlog>("blog_rss");
}

In den obigen Beispielen hat EF den Diskriminator implizit als Schatteneigenschaft für die Basisentität der Hierarchie hinzugefügt. Diese Eigenschaft kann wie jede andere konfiguriert werden:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property("Discriminator")
        .HasMaxLength(200);
}

Schließlich kann der Diskriminator auch einer regulären .NET-Eigenschaft in Ihrer Entität zugeordnet werden:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasDiscriminator(b => b.BlogType);

    modelBuilder.Entity<Blog>()
        .Property(e => e.BlogType)
        .HasMaxLength(200)
        .HasColumnName("blog_type");
}

Beim Abfragen von abgeleiteten Entitäten, die das TPH-Muster verwenden, fügt EF Core der Abfrage ein Prädikat über die Diskriminatorspalte hinzu. Dieser Filter stellt sicher, dass keine zusätzlichen Zeilen für Basistypen oder gleichgeordnete Typen angezeigt werden, die nicht im Ergebnis enthalten sind. Dieses Filterprädikat wird für den Basisentitätstyp übersprungen, da die Abfrage nach der Basisentität Ergebnisse für alle Entitäten in der Hierarchie erhält. Wenn wir beim Materialisieren von Ergebnissen aus einer Abfrage auf einen Diskriminatorwert stoßen, der keinem Entitätstyp im Modell zugeordnet ist, lösen wir eine Ausnahme aus, da wir nicht wissen, wie die Ergebnisse materialisiert werden sollen. Dieser Fehler tritt nur auf, wenn Ihre Datenbank Zeilen mit Diskriminatorwerten enthält, die im EF-Modell nicht zugeordnet sind. Wenn Sie über solche Daten verfügen, können Sie die Diskriminatorzuordnung im EF Core-Modell als unvollständig markieren, um anzugeben, dass wir immer filter prädikat hinzufügen sollten, um einen beliebigen Typ in der Hierarchie abzufragen. IsComplete(false) der Aufruf der Diskriminatorkonfiguration markiert, dass die Zuordnung unvollständig ist.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasDiscriminator()
        .IsComplete(false);
}

Freigegebene Spalten

Wenn zwei gleichgeordnete Entitätstypen in der Hierarchie über eine Eigenschaft mit demselben Namen verfügen, werden sie standardmäßig zwei separaten Spalten zugeordnet. Wenn ihr Typ jedoch identisch ist, können sie der gleichen Datenbankspalte zugeordnet werden:

public class MyContext : DbContext
{
    public DbSet<BlogBase> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .Property(b => b.Url)
            .HasColumnName("Url");

        modelBuilder.Entity<RssBlog>()
            .Property(b => b.Url)
            .HasColumnName("Url");
    }
}

public abstract class BlogBase
{
    public int BlogId { get; set; }
}

public class Blog : BlogBase
{
    public string Url { get; set; }
}

public class RssBlog : BlogBase
{
    public string Url { get; set; }
}

Hinweis

Relationale Datenbankanbieter, wie z. B. SQL Server, verwenden nicht automatisch das Diskriminator-Prädikat, wenn sie freigegebene Spalten abfragen, wenn eine Umwandlung verwendet wird. Die Abfrage Url = (blog as RssBlog).Url würde auch den Url Wert für die gleichgeordneten Blog Zeilen zurückgeben. Um die Abfrage auf Entitäten einzuschränken RssBlog , müssen Sie manuell einen Filter für den Diskriminator hinzufügen, z Url = blog is RssBlog ? (blog as RssBlog).Url : null. B. .

Konfiguration der Tabelle pro Typ

Im TPT-Zuordnungsmuster werden alle Typen einzelnen Tabellen zugeordnet. Eigenschaften, die nur zu einem Basistyp oder einem abgeleiteten Typ gehören, werden in einer Tabelle gespeichert, die diesem Typ zugeordnet ist. Tabellen, die abgeleiteten Typen zugeordnet sind, speichern auch einen Fremdschlüssel, der die abgeleitete Tabelle mit der Basistabelle verknüpft.

modelBuilder.Entity<Blog>().ToTable("Blogs");
modelBuilder.Entity<RssBlog>().ToTable("RssBlogs");

Tipp

Anstatt für jeden Entitätstyp aufzurufen ToTable , können Sie für jeden Stammentitätstyp aufrufen modelBuilder.Entity<Blog>().UseTptMappingStrategy() , und die Tabellennamen werden von EF generiert.

Tipp

Informationen zum Konfigurieren unterschiedlicher Spaltennamen für die Primärschlüsselspalten in jeder Tabelle finden Sie unter Tabellenspezifische Facetkonfiguration.

EF erstellt das folgende Datenbankschema für das oben genannte Modell.

CREATE TABLE [Blogs] (
    [BlogId] int NOT NULL IDENTITY,
    [Url] nvarchar(max) NULL,
    CONSTRAINT [PK_Blogs] PRIMARY KEY ([BlogId])
);

CREATE TABLE [RssBlogs] (
    [BlogId] int NOT NULL,
    [RssUrl] nvarchar(max) NULL,
    CONSTRAINT [PK_RssBlogs] PRIMARY KEY ([BlogId]),
    CONSTRAINT [FK_RssBlogs_Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blogs] ([BlogId]) ON DELETE NO ACTION
);

Hinweis

Wenn die Primärschlüsseleinschränkung umbenannt wird, wird der neue Name auf alle Tabellen angewendet, die der Hierarchie zugeordnet sind. Zukünftige EF-Versionen erlauben das Umbenennen der Einschränkung nur für eine bestimmte Tabelle, wenn Problem 19970 behoben ist.

Wenn Sie eine Massenkonfiguration verwenden, können Sie den Spaltennamen für eine bestimmte Tabelle abrufen, indem Sie aufrufen GetColumnName(IProperty, StoreObjectIdentifier).

foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
    var tableIdentifier = StoreObjectIdentifier.Create(entityType, StoreObjectType.Table);

    Console.WriteLine($"{entityType.DisplayName()}\t\t{tableIdentifier}");
    Console.WriteLine(" Property\tColumn");

    foreach (var property in entityType.GetProperties())
    {
        var columnName = property.GetColumnName(tableIdentifier.Value);
        Console.WriteLine($" {property.Name,-10}\t{columnName}");
    }

    Console.WriteLine();
}

Warnung

In vielen Fällen weist TPT eine schlechtere Leistung im Vergleich zu TPH auf. Weitere Informationen finden Sie in der Dokumentation zur Leistung.

Achtung

Spalten für einen abgeleiteten Typ werden verschiedenen Tabellen zugeordnet. Daher können in der Datenbank keine zusammengesetzten FK-Einschränkungen und Indizes erstellt werden, die sowohl die geerbten als auch die deklarierten Eigenschaften verwenden.

Konfiguration der Tabelle pro Konkretem Typ

Hinweis

Das TPC-Feature (Table Per Concrete Type) wurde in EF Core 7.0 eingeführt.

Im TPC-Zuordnungsmuster werden alle Typen einzelnen Tabellen zugeordnet. Jede Tabelle enthält Spalten für alle Eigenschaften des entsprechenden Entitätstyps. Dadurch werden einige häufige Leistungsprobleme mit der TPT-Strategie behoben.

Tipp

Das EF-Team hat in einer Folge des .NET Data Community Standups ausführlich über die TPC-Zuordnung demonstriert und darüber gesprochen. Wie bei allen Community Standup-Episoden können Sie die TPC-Episode jetzt auf YouTube ansehen.

modelBuilder.Entity<Blog>().UseTpcMappingStrategy()
    .ToTable("Blogs");
modelBuilder.Entity<RssBlog>()
    .ToTable("RssBlogs");

Tipp

Anstatt für jeden Entitätstyp aufzurufen ToTable , werden die Tabellennamen nach Konvention generiert, indem sie nur für jeden Stammentitätstyp aufrufen modelBuilder.Entity<Blog>().UseTpcMappingStrategy() .

Tipp

Informationen zum Konfigurieren unterschiedlicher Spaltennamen für die Primärschlüsselspalten in jeder Tabelle finden Sie unter Tabellenspezifische Facetkonfiguration.

EF erstellt das folgende Datenbankschema für das oben genannte Modell.

CREATE TABLE [Blogs] (
    [BlogId] int NOT NULL DEFAULT (NEXT VALUE FOR [BlogSequence]),
    [Url] nvarchar(max) NULL,
    CONSTRAINT [PK_Blogs] PRIMARY KEY ([BlogId])
);

CREATE TABLE [RssBlogs] (
    [BlogId] int NOT NULL DEFAULT (NEXT VALUE FOR [BlogSequence]),
    [Url] nvarchar(max) NULL,
    [RssUrl] nvarchar(max) NULL,
    CONSTRAINT [PK_RssBlogs] PRIMARY KEY ([BlogId])
);

TPC-Datenbankschema

Die TPC-Strategie ähnelt der TPT-Strategie, mit der Ausnahme, dass für jeden konkreten Typ in der Hierarchie eine andere Tabelle erstellt wird, tabellen jedoch nicht für abstrakte Typen erstellt werden – daher der Name "table-per-concrete-type". Wie bei TPT gibt die Tabelle selbst den Typ des gespeicherten Objekts an. Im Gegensatz zur TPT-Zuordnung enthält jede Tabelle Jedoch Spalten für jede Eigenschaft im konkreten Typ und die zugehörigen Basistypen. TPC-Datenbankschemas werden denormalisiert.

Ziehen Sie beispielsweise die Zuordnung dieser Hierarchie in Betracht:

public abstract class Animal
{
    protected Animal(string name)
    {
        Name = name;
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public abstract string Species { get; }

    public Food? Food { get; set; }
}

public abstract class Pet : Animal
{
    protected Pet(string name)
        : base(name)
    {
    }

    public string? Vet { get; set; }

    public ICollection<Human> Humans { get; } = new List<Human>();
}

public class FarmAnimal : Animal
{
    public FarmAnimal(string name, string species)
        : base(name)
    {
        Species = species;
    }

    public override string Species { get; }

    [Precision(18, 2)]
    public decimal Value { get; set; }

    public override string ToString()
        => $"Farm animal '{Name}' ({Species}/{Id}) worth {Value:C} eats {Food?.ToString() ?? "<Unknown>"}";
}

public class Cat : Pet
{
    public Cat(string name, string educationLevel)
        : base(name)
    {
        EducationLevel = educationLevel;
    }

    public string EducationLevel { get; set; }
    public override string Species => "Felis catus";

    public override string ToString()
        => $"Cat '{Name}' ({Species}/{Id}) with education '{EducationLevel}' eats {Food?.ToString() ?? "<Unknown>"}";
}

public class Dog : Pet
{
    public Dog(string name, string favoriteToy)
        : base(name)
    {
        FavoriteToy = favoriteToy;
    }

    public string FavoriteToy { get; set; }
    public override string Species => "Canis familiaris";

    public override string ToString()
        => $"Dog '{Name}' ({Species}/{Id}) with favorite toy '{FavoriteToy}' eats {Food?.ToString() ?? "<Unknown>"}";
}

public class Human : Animal
{
    public Human(string name)
        : base(name)
    {
    }

    public override string Species => "Homo sapiens";

    public Animal? FavoriteAnimal { get; set; }
    public ICollection<Pet> Pets { get; } = new List<Pet>();

    public override string ToString()
        => $"Human '{Name}' ({Species}/{Id}) with favorite animal '{FavoriteAnimal?.Name ?? "<Unknown>"}'" +
           $" eats {Food?.ToString() ?? "<Unknown>"}";
}

Wenn Sie SQL Server verwenden, werden folgende Tabellen für diese Hierarchie erstellt:

CREATE TABLE [Cats] (
    [Id] int NOT NULL DEFAULT (NEXT VALUE FOR [AnimalSequence]),
    [Name] nvarchar(max) NOT NULL,
    [FoodId] uniqueidentifier NULL,
    [Vet] nvarchar(max) NULL,
    [EducationLevel] nvarchar(max) NOT NULL,
    CONSTRAINT [PK_Cats] PRIMARY KEY ([Id]));

CREATE TABLE [Dogs] (
    [Id] int NOT NULL DEFAULT (NEXT VALUE FOR [AnimalSequence]),
    [Name] nvarchar(max) NOT NULL,
    [FoodId] uniqueidentifier NULL,
    [Vet] nvarchar(max) NULL,
    [FavoriteToy] nvarchar(max) NOT NULL,
    CONSTRAINT [PK_Dogs] PRIMARY KEY ([Id]));

CREATE TABLE [FarmAnimals] (
    [Id] int NOT NULL DEFAULT (NEXT VALUE FOR [AnimalSequence]),
    [Name] nvarchar(max) NOT NULL,
    [FoodId] uniqueidentifier NULL,
    [Value] decimal(18,2) NOT NULL,
    [Species] nvarchar(max) NOT NULL,
    CONSTRAINT [PK_FarmAnimals] PRIMARY KEY ([Id]));

CREATE TABLE [Humans] (
    [Id] int NOT NULL DEFAULT (NEXT VALUE FOR [AnimalSequence]),
    [Name] nvarchar(max) NOT NULL,
    [FoodId] uniqueidentifier NULL,
    [FavoriteAnimalId] int NULL,
    CONSTRAINT [PK_Humans] PRIMARY KEY ([Id]));

Beachten Sie Folgendes:

  • Es gibt keine Tabellen für die Animal - oder Pet -Typen, da diese im Objektmodell enthalten sind abstract . Denken Sie daran, dass C# keine Instanzen von abstrakten Typen zulässt und daher keine Instanz des abstrakten Typs in der Datenbank gespeichert wird.

  • Die Zuordnung von Eigenschaften in Basistypen wird für jeden konkreten Typ wiederholt. Beispielsweise verfügt jede Tabelle über eine Name Spalte, und sowohl Cats als auch Dogs haben eine Vet Spalte.

  • Das Speichern einiger Daten in dieser Datenbank führt zu Folgendem:

Cats-Tabelle

Id Name FoodId Tierarzt EducationLevel
1 Alina 99ca3e98-b26d-4a0c-d4ae-08da7aca624f Pengelly MBA
2 Mac 99ca3e98-b26d-4a0c-d4ae-08da7aca624f Pengelly Vorschule
8 Baxter 5dc5019e-6f72-454b-d4b0-08da7aca624f Bothell Pet Hospital Bsc

Hundetisch

Id Name FoodId Tierarzt FavoriteToy
3 Popupbenachrichtigung 011aaf6f-d588-4fad-d4ac-08da7aca624f Pengelly Herr Squirrel

FarmAnimals-Tabelle

Id Name FoodId Wert Tierart
4 Clyde 1d495075-f527-4498-d4af-08da7aca624f 100,00 Equus africanus asinus

Tabelle "Menschen"

Id Name FoodId FavoriteAnimalId
5 Wendy 5418fd81-7660-432f-d4b1-08da7aca624f 2
6 Arthur 59b495d4-0414-46bf-d4ad-08da7aca624f 1
9 Katie NULL 8

Beachten Sie, dass im Gegensatz zur TPT-Zuordnung alle Informationen für ein einzelnes Objekt in einer einzelnen Tabelle enthalten sind. Im Gegensatz zur TPH-Zuordnung gibt es keine Kombination aus Spalte und Zeile in einer Tabelle, in der das Modell nie verwendet wird. Im Folgenden erfahren Sie, wie diese Merkmale für Abfragen und Speicher wichtig sein können.

Schlüsselgenerierung

Die gewählte Vererbungszuordnungsstrategie hat Konsequenzen für die Generierung und Verwaltung von Primärschlüsselwerten. Schlüssel in TPH sind einfach, da jede Entitätsinstanz durch eine einzelne Zeile in einer einzelnen Tabelle dargestellt wird. Es kann jede Art von Schlüsselwertgenerierung verwendet werden, und es sind keine zusätzlichen Einschränkungen erforderlich.

Für die TPT-Strategie gibt es immer eine Zeile in der Tabelle, die dem Basistyp der Hierarchie zugeordnet ist. In dieser Zeile kann jede Art von Schlüsselgenerierung verwendet werden, und die Schlüssel für andere Tabellen sind mit dieser Tabelle mithilfe von Fremdschlüsseleinschränkungen verknüpft.

Für TPC wird es etwas komplizierter. Zunächst ist es wichtig zu verstehen, dass EF Core erfordert, dass alle Entitäten in einer Hierarchie über einen eindeutigen Schlüsselwert verfügen, auch wenn die Entitäten unterschiedliche Typen aufweisen. Wenn Sie beispielsweise unser Beispielmodell verwenden, kann ein Hund nicht den gleichen ID-Schlüsselwert wie eine Katze haben. Zweitens gibt es im Gegensatz zu TPT keine gemeinsame Tabelle, die als einzelner Ort fungieren kann, an dem Schlüsselwerte leben und generiert werden können. Dies bedeutet, dass eine einfache Identity Spalte nicht verwendet werden kann.

Für Datenbanken, die Sequenzen unterstützen, können Schlüsselwerte mithilfe einer einzelnen Sequenz generiert werden, auf die in der Standardeinschränkung für jede Tabelle verwiesen wird. Dies ist die Strategie, die in den oben gezeigten TPC-Tabellen verwendet wird, wobei jede Tabelle Folgendes aufweist:

[Id] int NOT NULL DEFAULT (NEXT VALUE FOR [AnimalSequence])

AnimalSequence ist eine datenbanksequenz, die von EF Core erstellt wurde. Diese Strategie wird standardmäßig für TPC-Hierarchien verwendet, wenn der EF Core-Datenbankanbieter für SQL Server verwendet wird. Datenbankanbieter für andere Datenbanken, die Sequenzen unterstützen, sollten eine ähnliche Standardeinstellung aufweisen. Andere Schlüsselgenerierungsstrategien, die Sequenzen verwenden, z. B. Hi-Lo-Muster, können auch mit TPC verwendet werden.

Obwohl Standardidentitätsspalten nicht mit TPC funktionieren, ist es möglich, Identitätsspalten zu verwenden, wenn jede Tabelle mit einem entsprechenden Seed- und Inkrement konfiguriert ist, sodass die für jede Tabelle generierten Werte nie in Konflikt treten. Beispiel:

modelBuilder.Entity<Cat>().ToTable("Cats", tb => tb.Property(e => e.Id).UseIdentityColumn(1, 4));
modelBuilder.Entity<Dog>().ToTable("Dogs", tb => tb.Property(e => e.Id).UseIdentityColumn(2, 4));
modelBuilder.Entity<FarmAnimal>().ToTable("FarmAnimals", tb => tb.Property(e => e.Id).UseIdentityColumn(3, 4));
modelBuilder.Entity<Human>().ToTable("Humans", tb => tb.Property(e => e.Id).UseIdentityColumn(4, 4));

Wichtig

Die Verwendung dieser Strategie macht es schwieriger, abgeleitete Typen später hinzuzufügen, da die Gesamtzahl der Typen in der Hierarchie vorher bekannt sein muss.

SQLite unterstützt keine Sequenzen oder Identity Seed/Increment, und daher wird die Generierung ganzzahliger Schlüsselwerte bei Verwendung von SQLite mit der TPC-Strategie nicht unterstützt. Clientseitige Generierung oder global eindeutige Schlüssel ( z. B. GUIDs ) werden jedoch in jeder Datenbank unterstützt, einschließlich SQLite.

Fremdschlüsseleinschränkungen

Die TPC-Zuordnungsstrategie erstellt ein denormalisiertes SQL-Schema – dies ist ein Grund, warum einige Datenbank puristen dagegen sind. Betrachten Sie beispielsweise die Fremdschlüsselspalte FavoriteAnimalId. Der Wert in dieser Spalte muss mit dem Primärschlüsselwert eines Tieres übereinstimmen. Dies kann in der Datenbank mit einer einfachen FK-Einschränkung erzwungen werden, wenn TPH oder TPT verwendet wird. Beispiel:

CONSTRAINT [FK_Animals_Animals_FavoriteAnimalId] FOREIGN KEY ([FavoriteAnimalId]) REFERENCES [Animals] ([Id])

Bei Verwendung von TPC wird jedoch der Primärschlüssel für ein bestimmtes Tier in der Tabelle gespeichert, die dem konkreten Typ dieses Tieres entspricht. Beispielsweise wird der Primärschlüssel einer Katze in der Cats.Id Spalte gespeichert, während der Primärschlüssel eines Hundes in der Dogs.Id Spalte gespeichert wird usw. Dies bedeutet, dass für diese Beziehung keine FK-Einschränkung erstellt werden kann.

In der Praxis ist dies kein Problem, solange die Anwendung nicht versucht, ungültige Daten einzufügen. Wenn beispielsweise alle Daten von EF Core eingefügt werden und Navigationsfunktionen zum Verknüpfen von Entitäten verwenden, ist garantiert, dass die FK-Spalte jederzeit gültige PK-Werte enthält.

Zusammenfassung und Anleitung

Zusammenfassend lässt sich sagen, dass TPH für die meisten Anwendungen in Ordnung ist und ein guter Standardwert für eine Vielzahl von Szenarien ist. Fügen Sie also nicht die Komplexität von TPC hinzu, wenn Sie sie nicht benötigen. Insbesondere, wenn Ihr Code hauptsächlich Entitäten vieler Typen abfragt, z. B. das Schreiben von Abfragen für den Basistyp, dann tendieren Sie zu TPH über TPC.

Allerdings ist TPC auch eine gute Zuordnungsstrategie, wenn Ihr Code hauptsächlich Entitäten eines einzelnen Blatttyps abfragen wird und Ihre Benchmarks eine Verbesserung im Vergleich zu TPH zeigen.

Verwenden Sie TPT nur, wenn dies durch externe Faktoren eingeschränkt ist.