Datenseeding

Das Datensamen ist der Vorgang, eine Datenbank mit einer ersten Datenmenge aufzufüllen.

Es gibt verschiedene Möglichkeiten, wie dies in EF Core erreicht werden kann:

  • Modell-Seeddaten
  • Manuelle Migrationsanpassung
  • Benutzerdefinierte Initialisierungslogik

Modell-Seeddaten

Im Gegensatz zu EF6 können Seedingdaten in EF Core einem Entitätstyp als Teil der Modellkonfiguration zugeordnet werden. Dann kann EF Core-Migrationen automatisch berechnen, welche Einfüge-, Aktualisierungs- oder Löschvorgänge beim Upgrade der Datenbank auf eine neue Version des Modells angewendet werden müssen.

Hinweis

Migrationen berücksichtigt nur Modelländerungen, wenn sie bestimmen, welche Operation ausgeführt werden soll, um die Seeddaten in den gewünschten Zustand zu erhalten. Daher können änderungen an den außerhalb von Migrationen ausgeführten Daten verloren gehen oder einen Fehler verursachen.

In diesem Beispiel werden die Seeddaten für ein Blog In OnModelCreatingkonfiguriert:

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 über Eigenschaften im Schattenzustand verfügt, 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" });

Besitzer-Entitätstypen können in ähnlicher Weise abgesent 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 .

Sobald 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 context.Database.EnsureCreated() Sie 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 noch die Seeddaten in der Datenbank aktualisiert werden. Bei relationalen Datenbanken sollten Sie nicht aufrufen EnsureCreated() , wenn Sie Migrationen verwenden möchten.

Einschränkungen von Modellsamendaten

Dieser Typ von Seeddaten wird durch Migrationen verwaltet, und das Skript zum Aktualisieren der Daten, die bereits in der Datenbank vorhanden sind, muss generiert werden, ohne eine Verbindung mit der Datenbank herzustellen. Dies setzt einige Einschränkungen ein:

  • Der Primärschlüsselwert muss angegeben werden, auch wenn er in der Regel von der Datenbank generiert wird. Es wird verwendet, um Datenänderungen zwischen Migrationen zu erkennen.
  • Zuvor werden die daten mit Dem Seeded-Element entfernt, wenn der Primärschlüssel in irgendeiner Weise geändert wird.

Daher ist dieses Feature am nützlichsten für statische Daten, 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 eine der folgenden Elemente 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 (Seeding-Daten 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 benutzerdefinierte Transformation erfordern (die nicht durch Wertkonvertierungen behandelt werden), z. B. einige Kennworthashing
  • Daten, die Aufrufe einer externen API erfordern, z. B. ASP.NET Core Identitätsrollen und Benutzererstellung

Manuelle Migrationsanpassung

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

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

Benutzerdefinierte Initialisierungslogik

Eine einfache und leistungsstarke Methode zum Ausführen von Datensamen besteht darin, vor beginn der Ausführung der Hauptanwendungslogik zu verwenden DbContext.SaveChanges() .

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 dies zu Parallelitätsproblemen führen kann, wenn mehrere Instanzen ausgeführt werden und die App auch über die Berechtigung zum Ändern des Datenbankschemas verfügen muss.

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

  • Lokales Ausführen der Initialisierungs-App
  • Stellen Sie die Initialisierungs-App mit der Haupt-App bereit, indem Sie die Initialisierungsroutine aufrufen und die Initialisierungs-App deaktivieren oder entfernen.

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