Datenseeding

Bei der Dateineinspeisung handelt es sich um den Prozess, bei dem eine Datenbank mit einem anfänglichen Datensatz gefüllt wird.

Es gibt verschiedene Möglichkeiten, dies in EF Core zu erreichen:

  • Modellierung von Seeddaten
  • Manuelle Migrationsanpassung
  • Benutzerdefinierte Initialisierungslogik

Modellierung von Seeddaten

Im Gegensatz zu EF 6 kann das Datenseeding in EF Core mit einem Entitätstyp als Teil der Modellkonfiguration verknüpft werden. EF Core-Migrationen können dann automatisch berechnen, welche Einfüge-, Aktualisierungs- oder Löschvorgänge beim Durchführen eines Upgrades für die Datenbank auf eine neue Modellversion angewendet werden müssen.

Hinweis

Bei Migrationen werden Modelländerungen nur berücksichtigt, wenn ermittelt wird, welcher Vorgang ausgeführt werden soll, um die Seeddaten in den gewünschten Zustand zu bringen. Daher können Änderungen an den außerhalb von Migrationen ausgeführten Daten verloren gehen oder einen Fehler verursachen.

So werden zum Beispiel Seeddaten von Blog in OnModelCreating konfiguriert:

modelBuilder.Entity<Blog>().HasData(new Blog { BlogId = 1, Url = "http://sample.com" });

Um Entitäten hinzuzufügen, die über eine Beziehung verfügen, müssen die Fremdschlüsselwerte angegeben werden:

modelBuilder.Entity<Post>().HasData(
    new Post { BlogId = 1, PostId = 1, Title = "First post", Content = "Test 1" });

Wenn der Entitätstyp Eigenschaften im Schattenzustand besitzt, kann eine anonyme Klasse verwendet werden, um die Werte bereitzustellen:

modelBuilder.Entity<Post>().HasData(
    new { BlogId = 1, PostId = 2, Title = "Second post", Content = "Test 2" });

Für nicht eigenständige Entitätstypen kann auf ähnliche Weise ein Seeding durchgeführt werden:

modelBuilder.Entity<Post>().OwnsOne(p => p.AuthorName).HasData(
    new { PostId = 1, First = "Andriy", Last = "Svyryd" },
    new { PostId = 2, First = "Diego", Last = "Vega" });

Weitere Kontexte finden Sie im vollständigen Beispielprojekt.

Nachdem die Daten dem Modell hinzugefügt wurden, sollten Migrationen verwendet werden, um die Änderungen anzuwenden.

Tipp

Wenn Sie Migrationen als Teil einer automatisierten Bereitstellung anwenden müssen, können Sie ein SQL-Skript erstellen, das vor der Ausführung in der Vorschau angezeigt werden kann.

Alternativ können Sie mithilfe von context.Database.EnsureCreated() eine neue Datenbank erstellen, die die Seeddaten enthält, z. B. für eine Testdatenbank oder bei Verwendung des In-Memory-Anbieters oder einer nicht relationalen Datenbank. Beachten Sie, dass, wenn die Datenbank bereits vorhanden ist, EnsureCreated() weder das Schema aktualisieren noch ein Seeding für Daten in der Datenbank durchführen kann. Bei relationalen Datenbanken sollten Sie EnsureCreated() nicht aufrufen, wenn Sie Migrationen verwenden möchten.

Einschränkungen von Modellseeddaten

Diese Art von Seeddaten wird von Migrationen verwaltet, und das Skript zum Aktualisieren der Daten, die sich bereits in der Datenbank befinden, muss generiert werden, ohne eine Verbindung mit der Datenbank herzustellen. Dies erzwingt einige Einschränkungen:

  • Der Primärschlüsselwert muss angegeben werden, auch wenn er normalerweise von der Datenbank generiert wird. Er wird verwendet, um Datenänderungen zwischen Migrationen zu erkennen.
  • Zuvor per Seeding hinzugefügte Daten werden entfernt, wenn der Primärschlüssel geändert wird.

Daher ist dieses Feature für statische Daten am nützlichsten, die nicht außerhalb von Migrationen geändert werden sollen, und hängt nicht von anderen Elementen in der Datenbank ab, z. B. Postleitzahlen.

Wenn Ihr Szenario einen der folgenden Datentypen enthält, empfiehlt es sich, benutzerdefinierte Initialisierungslogik zu verwenden, die im letzten Abschnitt beschrieben wird:

  • Temporäre Daten für Tests
  • Daten, die vom Datenbankstatus abhängen
  • Daten, die groß sind (Seedingdaten werden in Migrationsmomentaufnahmen erfasst, und große Daten können schnell zu riesigen Dateien und beeinträchtigter Leistung führen.)
  • Daten, die von der Datenbank generiert werden müssen, einschließlich Entitäten, die alternative Schlüssel als Identität verwenden
  • Daten, die eine benutzerdefinierte Transformation erfordern (die von Wertkonvertierungen nicht behandelt werden), z. B. Kennworthashing in irgend einer Form
  • Daten, die Aufrufe an externe API erfordern, z. B. ASP.NET Core Identity-Rollen und -Benutzererstellung

Manuelle Migrationsanpassung

Wenn eine Migration hinzugefügt wird, werden die Änderungen an den mit HasData angegebenen Daten in Aufrufe von InsertData(), UpdateData() und DeleteData() transformiert. Eine Möglichkeit, um einige der Einschränkungen von HasData zu umgehen, besteht darin, stattdessen diese Aufrufe oder benutzerdefinierte Vorgänge der Migration manuell hinzuzufügen.

migrationBuilder.InsertData(
    table: "Blogs",
    columns: new[] { "Url" },
    values: new object[] { "http://generated.com" });

Benutzerdefinierte Initialisierungslogik

Eine einfache und leistungsstarke Möglichkeit zum Ausführen von Datenseeding besteht darin, DbContext.SaveChanges() zu verwenden, bevor die Hauptanwendungslogik mit der Ausführung beginnt.

using (var context = new DataSeedingContext())
{
    context.Database.EnsureCreated();

    var testBlog = context.Blogs.FirstOrDefault(b => b.Url == "http://test.com");
    if (testBlog == null)
    {
        context.Blogs.Add(new Blog { Url = "http://test.com" });
    }

    context.SaveChanges();
}

Warnung

Der Seedingcode sollte nicht Teil der normalen App-Ausführung sein, da er zu Parallelitätsproblemen führen kann, wenn mehrere Instanzen ausgeführt werden. Außerdem müsste die App über die Berechtigung zum Ändern des Datenbankschemas verfügen.

Abhängig von den Einschränkungen Ihrer Bereitstellung kann der Initialisierungscode auf unterschiedliche Weise ausgeführt werden:

  • Lokales Ausführen der Initialisierungs-App
  • Bereitstellen der Initialisierungs-App mit der Haupt-App, Aufrufen der Initialisierungsroutine und Deaktivieren oder Entfernen der Initialisierungs-App

Dieser Vorgang kann in der Regel mithilfe von Veröffentlichungsprofilen automatisiert werden.