Übung: Einrichten einer Migration

Abgeschlossen

In dieser Lerneinheit erstellen Sie C#-Entitätsklassen, die Tabellen in einer lokalen SQLite-Datenbank zugeordnet werden. Das EF Core-Migrationsfeature erstellt Tabellen aus diesen Entitäten.

Eine Migration bietet eine Möglichkeit, das Datenbankschema inkrementell zu aktualisieren.

Abrufen der Projektdateien

Rufen Sie zunächst die Projektdateien ab. Es gibt verschiedene Möglichkeiten, die Projektdateien abzurufen:

  • Verwenden von GitHub Codespaces
  • Klonen des GitHub-Repositorys

Wenn Sie eine kompatible Containerruntime installiert haben, können Sie auch die Dev Containers-Erweiterung verwenden, um das Repository in einem Container mit vorinstallierten Tools zu öffnen.

Verwenden von GitHub Codespaces

Ein Codespace ist eine in der Cloud gehostete IDE. Wenn Sie GitHub Codespaces verwenden, wechseln Sie zum Repository in Ihrem Browser. Wählen Sie Code aus, und erstellen Sie dann einen neuen Codespace im main-Branch.

Klonen des GitHub-Repositorys

Wenn Sie GitHub Codespaces nicht verwenden, können Sie das GitHub-Projektrepository klonen und die Dateien dann als Ordner in Visual Studio Code öffnen.

  1. Öffnen Sie ein Befehlsterminal, und klonen Sie dann das Projekt aus GitHub mithilfe der Eingabeaufforderung:

    git clone https://github.com/MicrosoftDocs/mslearn-persist-data-ef-core
    
  2. Wechseln Sie zum Ordner mslearn-persist-data-ef-core, und öffnen Sie dann das Projekt in Visual Studio Code:

    cd mslearn-persist-data-ef-core
    code .
    

Überprüfen des Codes

Nachdem Sie nun über die Projektdateien verfügen, mit denen Sie arbeiten können, sehen wir uns an, was im Projekt enthalten ist, und überprüfen den Code.

  • Das ASP.NET Core-Web-API-Projekt, die sich im Verzeichnis ContosoPizza befindet. Die Dateipfade, auf die wir in diesem Modul verweisen, sind relativ zum ContosoPizza-Verzeichnis.
  • Services/PizzaService.cs ist eine Dienstklasse, die CRUD-Methoden definiert. Alle Methoden lösen zurzeit eine System.NotImplementedException aus.
  • In Program.cs ist PizzaService über das Abhängigkeitsinjektionssystem von ASP.NET Core registriert.
  • Controllers/PizzaController.cs ist ein Wert für ApiController, der einen Endpunkt für die HTTP-Verben „POST“, „GET“, „PUT“ und „DELETE“ verfügbar macht. Diese Verben rufen die entsprechenden CRUD-Methoden für PizzaService auf. PizzaService wird in den Konstruktor PizzaController eingefügt.
  • Der Ordner Modelle enthält die Modelle, die von PizzaService und PizzaController verwendet werden.
  • Die Entitätsmodelle Pizza.cs, Topping.cs und Sauce.cs weisen die folgenden Beziehungen auf:
    • Eine Pizza kann mit einer oder mehreren Zutaten belegt sein.
    • Ein Belag kann auf einer oder mehreren Pizzas verwendet werden.
    • Eine Pizza kann nur eine Soße aufweisen, aber eine Soße kann auf vielen Pizzas verwendet werden.

Erstellen der App

Gehen Sie wie folgt vor, um die App in Visual Studio Code zu erstellen:

  1. Klicken Sie im Bereich Explorer mit der rechten Maustaste auf das Verzeichnis ContosoPizza, und wählen Sie In integriertem Terminal öffnen aus.

    Dadurch wird ein Terminalbereich für das Verzeichnis ContosoPizza geöffnet.

  2. Verwenden Sie den folgenden Befehl, um die App zu erstellen:

    dotnet build
    

    Der Code sollte ohne Warnungen oder Fehler erstellt werden.

Hinzufügen von NuGet-Paketen und EF Core-Tools

Die Datenbank-Engine, mit der Sie in diesem Modul arbeiten, ist SQLite. SQLite ist eine schlanke, dateibasierte Datenbank-Engine. Sie eignet sich gut für Entwicklung und Tests, aber auch für kleine Produktionsbereitstellungen.

Hinweis

Wie bereits erwähnt, können Datenbankanbieter in EF Core ergänzt werden. SQLite ist eine gute Wahl für dieses Modul, da es schlank und plattformübergreifend ist. Sie können denselben Code verwenden, um verschiedene andere Datenbank-Engines wie SQL Server und PostgreSQL zu verwenden. Sie können sogar mehrere Datenbank-Engines in derselben App verwenden.

Bevor Sie beginnen, fügen Sie die erforderlichen Pakete hinzu:

  1. Führen Sie im Terminalbereich den folgenden Befehl aus:

    dotnet add package Microsoft.EntityFrameworkCore.Sqlite
    

    Dieser Befehl fügt das NuGet-Paket hinzu, das den EF Core-SQLite-Datenbankanbieter und alle zugehörigen Abhängigkeiten enthält, einschließlich der allgemeinen EF Core-Dienste.

  2. Führen Sie als Nächstes diesen Befehl aus:

    dotnet add package Microsoft.EntityFrameworkCore.Design
    

    Dieser Befehl fügt Pakete hinzu, die für die EF Core-Tools erforderlich sind.

  3. Führen Sie zum Abschluss den folgenden Befehl aus:

    dotnet tool install --global dotnet-ef
    

    Dieser Befehl installiert dotnet ef, das Tool, mit dem Sie Migrationen und Gerüstbau erstellen.

    Tipp

    Wenn dotnet ef bereits installiert ist, können Sie dieses Tool aktualisieren, indem Sie dotnet tool update --global dotnet-ef ausführen.

Modellgerüste und DbContext

Jetzt fügen Sie eine DbContext-Implementierung hinzu und konfigurieren diese. DbContext ist ein Gateway, über das Sie mit der Datenbank interagieren können.

  1. Klicken Sie mit der rechten Maustaste auf das Verzeichnis ContosoPizza, und fügen Sie einen neuen Ordner namens Data hinzu.

  2. Erstellen Sie im Ordner Data eine neue Datei namens PizzaContext.cs. Fügen Sie der leeren Datei den folgenden Code hinzu:

    using Microsoft.EntityFrameworkCore;
    using ContosoPizza.Models;
    
    namespace ContosoPizza.Data;
    
    public class PizzaContext : DbContext
    {
        public PizzaContext (DbContextOptions<PizzaContext> options)
            : base(options)
        {
        }
    
        public DbSet<Pizza> Pizzas => Set<Pizza>();
        public DbSet<Topping> Toppings => Set<Topping>();
        public DbSet<Sauce> Sauces => Set<Sauce>();
    }
    

    Für den Code oben gilt:

    • Der Konstruktor akzeptiert einen Parameter vom Typ DbContextOptions<PizzaContext>. Durch den Konstruktor kann externer Code an die Konfiguration übergeben werden, sodass dasselbe DbContext-Element von Test- und Produktionscode gemeinsam genutzt und sogar mit verschiedenen Anbietern verwendet werden kann.
    • Die DbSet<T>-Eigenschaften entsprechen Tabellen, die in der Datenbank erstellt werden sollen.
    • Die Tabellennamen stimmen mit den Eigenschaftsnamen „DbSet<T>“ in der Klasse „PizzaContext“ überein. Sie können dieses Verhalten bei Bedarf außer Kraft setzen.
    • Bei der Instanziierung macht PizzaContext die Eigenschaften „Pizzas“, „Toppings“ und „Sauces“ verfügbar. Änderungen, die Sie an den Auflistungen vornehmen, die diese Eigenschaften verfügbar machen, werden an die Datenbank weitergegeben.
  3. Ersetzen Sie // Add the PizzaContext in der Datei Program.cs durch den folgenden Code:

    builder.Services.AddSqlite<PizzaContext>("Data Source=ContosoPizza.db");
    

    Der obige Code:

    • PizzaContext wird mit dem ASP.NET Core-Abhängigkeitsinjektionssystem registriert.
    • Gibt an, dass PizzaContext den SQLite-Datenbankanbieter verwendet.
    • Definiert eine SQLite-Verbindungszeichenfolge, die auf die lokale Datei ContosoPizza.db verweist.

    Hinweis

    Da SQLite lokale Datenbankdateien verwendet, stellt die Hartcodierung der Verbindungszeichenfolge kein Problem dar. Für Netzwerkdatenbanken wie PostgreSQL und SQL Server sollten Sie Ihre Verbindungszeichenfolgen grundsätzlich sicher speichern. Verwenden Sie für die lokale Entwicklung den Secret Manager. Bei Produktionsbereitstellungen sollten Sie einen Dienst wie Azure Key Vault in Betracht ziehen.

  4. Ersetzen Sie zudem // Additional using declarations in der Datei Program.cs durch den folgenden Code.

    using ContosoPizza.Data;
    

    Dieser Code löst Abhängigkeiten aus dem vorherigen Schritt auf.

  5. Speichern Sie alle Änderungen. GitHub Codespaces speichert Ihre Änderungen automatisch.

  6. Erstellen Sie die App im Terminal, indem Sie dotnet build ausführen. Der Buildvorgang sollte erfolgreich und ohne Warnungen oder Fehler abgeschlossen werden.

Erstellen und Ausführen einer Migration

Als Nächstes erstellen Sie eine Migration, mit der Sie Ihre anfängliche Datenbank erstellen können.

  1. Führen Sie im dem Gültigkeitsbereich des ContosoPizza-Projektordners zugeordneten Terminal den folgenden Befehl aus, um eine Migration zum Erstellen der Datenbanktabellen zu generieren:

    dotnet ef migrations add InitialCreate --context PizzaContext
    

    Für den obigen Befehl gilt Folgendes:

    • Die Migration heißt „InitialCreate“.
    • Die Option --context gibt den Namen der Klasse im Projekt ContosoPizza an, der von DbContext abgeleitet wird.

    Im Projektstamm ContosoPizza wird ein neues Verzeichnis Migrations angezeigt. Das Verzeichnis enthält die Datei <timestamp>_InitialCreate.cs, die Datenbankänderungen beschreibt, die in ein Datendefinitionssprache-Änderungsskript (Data Definition Language, DDL) übersetzt werden sollen.

  2. Führen Sie den folgenden Befehl aus, um die Migration InitialCreate anzuwenden:

    dotnet ef database update --context PizzaContext
    

    Mit diesem Befehl wird die Migration angewendet. Da ContosoPizza.db nicht vorhanden ist, erstellt dieser Befehl die Migration im Projektverzeichnis.

    Tipp

    Alle Plattformen unterstützen das dotnet ef-Tool. In Visual Studio unter Windows können Sie die PowerShell-Cmdlets Add-Migration und Update-Database im integrierten Fenster der Paket-Manager-Konsole verwenden.

Untersuchen der Datenbank

EF Core hat eine Datenbank für Ihre App erstellt. Als Nächstes sehen wir uns die Datenbank mithilfe der SQLite-Erweiterung genauer an.

  1. Klicken Sie im Bereich Explorer mit der rechten Maustaste auf die Datei ContosoPizza.db, und wählen Sie Datenbank öffnen aus.

    Screenshot: Menüoption „Datenbank öffnen“ im Explorer-Bereich in Visual Studio Code

    Im Explorer-Bereich wird der Ordner SQLite Explorer angezeigt.

    Screenshot mit dem Ordner „SQLite Explorer“ im Explorer-Bereich.

  2. Wählen Sie den Ordner SQLite Explorer aus, um den Knoten und alle untergeordneten Knoten zu erweitern. Klicken Sie mit der rechten Maustaste auf ContosoPizza.db, und wählen Sie Tabelle „sqlite_master“ anzeigen aus, um das vollständige Datenbankschema und die Einschränkungen anzuzeigen, die von der Migration erstellt wurden.

    Screenshot: Erweiterter Ordner „SQLite Explorer“ im Explorer-Bereich

    • Es wurden Tabellen erstellt, die den einzelnen Entitäten entsprechen.
    • Tabellennamen wurden aus den Namen der DbSet-Eigenschaften für PizzaContext entnommen.
    • Eigenschaften namens Id wurden als automatisch inkrementierte Primärschlüsselfelder abgeleitet.
    • Die Namenskonventionen für Primärschlüssel- und Fremdschlüsseleinschränkungen von EF Core sind PK_<primary key property> bzw. FK_<dependent entity>_<principal entity>_<foreign key property>. Die Platzhalter <dependent entity> und <principal entity> entsprechen den Namen der Entitätsklasse.

    Hinweis

    Wie ASP.NET Core MVC verwendet EF Core einen Konvention-vor-Konfiguration-Ansatz. EF Core-Konventionen verkürzen die Entwicklungszeit, indem sie auf die Absicht des Entwicklers schließen. EF Core leitet beispielsweise eine Eigenschaft mit dem Namen Id oder <entity name>Id als Primärschlüssel der generierten Tabelle ab. Wenn Sie die Namenskonvention nicht übernehmen möchten, müssen Sie die Eigenschaft mit dem Attribut [Key] kommentieren oder als Schlüssel in der OnModelCreating-Methode von DbContext konfigurieren.

Ändern des Modells und Aktualisieren des Datenbankschemas

Ihre Vorgesetzten bei Contoso Pizza nennen Ihnen einige neue Anforderungen, weshalb Sie Ihre Entitätsmodelle ändern müssen. In den folgenden Schritten ändern Sie die Modelle mithilfe von Zuordnungsattributen (manchmal auch als Datenanmerkungen bezeichnet).

  1. Nehmen Sie in Models\Pizza.cs die folgenden Änderungen vor:

    1. Fügen Sie eine using-Anweisung für System.ComponentModel.DataAnnotations hinzu.
    2. Fügen Sie vor der Name-Eigenschaft ein [Required]-Attribut hinzu, um die Eigenschaft als erforderlich zu markieren.
    3. Fügen Sie vor der Name-Eigenschaft ein [MaxLength(100)]-Attribut hinzu, um eine maximale Zeichenfolgenlänge von 100 anzugeben.

    Ihre aktualisierte Pizza.cs-Datei sollte wie der folgende Code aussehen:

    using System.ComponentModel.DataAnnotations;
    
    namespace ContosoPizza.Models;
    
    public class Pizza
    {
        public int Id { get; set; }
    
        [Required]
        [MaxLength(100)]
        public string? Name { get; set; }
    
        public Sauce? Sauce { get; set; }
    
        public ICollection<Topping>? Toppings { get; set; }
    }
    
  2. Nehmen Sie in Models\Sauce.cs die folgenden Änderungen vor:

    1. Fügen Sie eine using-Anweisung für System.ComponentModel.DataAnnotations hinzu.
    2. Fügen Sie vor der Name-Eigenschaft ein [Required]-Attribut hinzu, um die Eigenschaft als erforderlich zu markieren.
    3. Fügen Sie vor der Name-Eigenschaft ein [MaxLength(100)]-Attribut hinzu, um eine maximale Zeichenfolgenlänge von 100 anzugeben.
    4. Fügen Sie eine bool-Eigenschaft namens IsVegan hinzu.

    Ihre aktualisierte Sauce.cs-Datei sollte wie der folgende Code aussehen:

    using System.ComponentModel.DataAnnotations;
    
    namespace ContosoPizza.Models;
    
    public class Sauce
    {
        public int Id { get; set; }
    
        [Required]
        [MaxLength(100)]
        public string? Name { get; set; }
    
        public bool IsVegan { get; set; }
    }
    
  3. Nehmen Sie in Models\Topping.cs die folgenden Änderungen vor:

    1. Fügen Sie using-Anweisungen für System.ComponentModel.DataAnnotations und System.Text.Json.Serialization hinzu.

    2. Fügen Sie vor der Name-Eigenschaft ein [Required]-Attribut hinzu, um die Eigenschaft als erforderlich zu markieren.

    3. Fügen Sie vor der Name-Eigenschaft ein [MaxLength(100)]-Attribut hinzu, um eine maximale Zeichenfolgenlänge von 100 anzugeben.

    4. Fügen Sie eine decimal-Eigenschaft namens Calories unmittelbar nach der Name-Eigenschaft hinzu.

    5. Fügen Sie eine Pizzas-Eigenschaft vom Typ „ICollection<Pizza>?“ hinzu. Diese Änderung macht aus Pizza-Topping eine m:n-Beziehung.

    6. Fügen Sie der Pizzas-Eigenschaft ein [JsonIgnore]-Attribut hinzu.

      Wichtig

      Dieses Attribut verhindert, dass Topping-Entitäten die Eigenschaft Pizzas einschließen, wenn der Web-API-Code die Antwort in JSON serialisiert. Ohne diese Änderung würde eine serialisierte Sammlung von Belägen eine Sammlung mit jeder Pizza enthalten, die den jeweiligen Belag verwendet. Jede Pizza in dieser Auflistung enthielte wiederum eine Auflistung von Belägen, die jeweils wieder eine Auflistung von Pizzas umfassen würde. Diese Art von Endlosschleife wird als Zirkelbezug bezeichnet und kann nicht serialisiert werden.

    Ihre aktualisierte Topping.cs-Datei sollte wie der folgende Code aussehen:

    using System.ComponentModel.DataAnnotations;
    using System.Text.Json.Serialization;
    
    namespace ContosoPizza.Models;
    
    public class Topping
    {
        public int Id { get; set; }
    
        [Required]
        [MaxLength(100)]
        public string? Name { get; set; }
    
        public decimal Calories { get; set; }
    
        [JsonIgnore]
        public ICollection<Pizza>? Pizzas { get; set; }
    }
    
  4. Speichern Sie alle Änderungen, und führen Sie dotnet build aus.

  5. Führen Sie den folgenden Befehl aus, um eine Migration zum Erstellen der Datenbanktabellen zu generieren:

    dotnet ef migrations add ModelRevisions --context PizzaContext
    

    Mit diesem Befehl wird eine Migration namens „ModelRevisions“ erstellt.

    Hinweis

    Ihnen wird diese Meldung angezeigt: An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy. (Ein Vorgang wurde erstellt, der zum Datenverlust führen kann. Überprüfen Sie die Migration auf Genauigkeit.) Diese Meldung wurde angezeigt, da Sie die Beziehung von Pizza in Topping von 1:n in m:n geändert haben, was erfordert, dass eine vorhandene Fremdschlüsselspalte gelöscht wird. Da in Ihrer Datenbank noch keine Daten vorhanden sind, ist diese Änderung nicht problematisch. Im Allgemeinen empfiehlt es sich jedoch, die generierte Migration zu überprüfen, wenn diese Warnung angezeigt wird, um sicherzustellen, dass die Migration keine Daten löscht oder abschneidet.

  6. Führen Sie den folgenden Befehl aus, um die Migration ModelRevisions anzuwenden:

    dotnet ef database update --context PizzaContext
    
  7. Klicken Sie auf der Titelleiste des Ordners SQLite Explorer auf die Schaltfläche Datenbanken aktualisieren.

    Screenshot: Schaltfläche „Datenbanken aktualisieren“ auf der Titelleiste des Ordners „SQLite Explorer“

  8. Klicken Sie im Ordner SQLite Explorer mit der rechten Maustaste auf ContosoPizza.db. Wählen Sie Tabelle „sqlite_master“ anzeigen aus, um das vollständige Datenbankschema und die Einschränkungen anzuzeigen.

    Wichtig

    Die SQLite-Erweiterung verwendet geöffnete SQLite-Registerkarten erneut.

    • Eine Jointabelle PizzaTopping wurde erstellt, um die m:n-Beziehung zwischen Pizzas und Belägen darzustellen.
    • Neue Felder wurden Toppings und Sauces hinzugefügt.
      • Calories wird als text-Spalte definiert, weil SQLite keinen entsprechenden decimal-Typ aufweist.
      • In ähnlicher Weise wird IsVegan als integer-Spalte definiert. SQLite definiert keinen bool-Typ.
      • In beiden Fällen verwaltet EF Core die Übersetzung.
    • Die Name-Spalte in jeder Tabelle wurde als not null markiert, SQLite weist jedoch keine MaxLength-Einschränkung auf.

    Tipp

    EF Core-Datenbankanbieter ordnen den Features einer bestimmten Datenbank ein Modellschema zu. Im Gegensatz zu anderen Datenbanken wie SQL Server und PostgreSQL implementiert SQLite keine entsprechende Einschränkung für MaxLength.

  9. Klicken Sie im Ordner SQLite Explorer mit der rechten Maustaste auf die Tabelle _EFMigrationsHistory, und wählen Sie Tabelle anzeigen aus. Die Tabelle enthält eine Liste aller Migrationen, die auf die Datenbank angewendet werden. Da Sie zwei Migrationsvorgänge ausgeführt haben, gibt es zwei Einträge: einen für die InitialCreate-Migration und einen zweiten für ModelRevisions.

Hinweis

In dieser Übung wurden Zuordnungsattribute (Datenanmerkungen) verwendet, um der Datenbank Modelle zuzuordnen. Alternativ zum Zuordnen von Attributen können Sie die Fluent-API „ModelBuilder“ verwenden, um Modelle zu konfigurieren. Beide Ansätze sind möglich, aber einige Entwickler*innen bevorzugen einen der beiden Ansätze.

Sie haben Migrationen verwendet, um ein Datenbankschema zu definieren und zu aktualisieren. In der nächsten Einheit stellen Sie die Methoden zur Datenbearbeitung in PizzaService fertig.

Überprüfen Sie Ihr Wissen

1.

Welche Namenskonvention für Eigenschaften gibt es in einer Entitätsklasse für einen Primärschlüssel?