Sdílet prostřednictvím


Část 4, Razor Stránky s migracemi EF Core v ASP.NET Core

Tom Dykstra, Jon P Smith a Rick Anderson

Webová aplikace Contoso University ukazuje, jak vytvářet Razor webové aplikace Pages pomocí EF Core sady Visual Studio. Informace o sérii kurzů najdete v prvním kurzu.

Pokud narazíte na problémy, které nemůžete vyřešit, stáhněte si dokončenou aplikaci a porovnejte tento kód s tím, co jste vytvořili podle kurzu.

Tento kurz představuje EF Core funkci migrace pro správu změn datového modelu.

Při vývoji nové aplikace se datový model často mění. Pokaždé, když se model změní, se model nesynchronizuje s databází. Tato série kurzů začala konfigurací entity Framework pro vytvoření databáze, pokud neexistuje. Pokaždé, když se datový model změní, je potřeba databázi vyhodit. Při příštím spuštění aplikace volání znovu EnsureCreated vytvoří databázi tak, aby odpovídala novému datovému modelu. Třída DbInitializer se pak spustí k osadí novou databázi.

Tento přístup k udržování databáze v synchronizaci s datovým modelem funguje dobře, dokud nebude potřeba aplikaci nasadit do produkčního prostředí. Když je aplikace spuštěná v produkčním prostředí, obvykle ukládá data, která je potřeba udržovat. Aplikace nemůže začít s testovací databází při každé změně (například přidáním nového sloupce). Funkce EF Core Migrace tento problém řeší povolením EF Core aktualizace schématu databáze místo vytvoření nové databáze.

Místo vyřazení a opětovného vytvoření databáze při změně datového modelu migrace aktualizuje schéma a zachová stávající data.

Poznámka:

Omezení SQLite

V tomto kurzu se používá funkce migrace Entity Framework Core, pokud je to možné. Migrace aktualizuje schéma databáze tak, aby odpovídalo změnám datového modelu. Migrace však provádějí pouze druhy změn, které databázový stroj podporuje, a možnosti změny schématu SQLite jsou omezené. Přidání sloupce se například podporuje, ale odebrání sloupce se nepodporuje. Pokud se vytvoří migrace, která odebere sloupec, příkaz bude úspěšný, ef migrations add ale ef database update příkaz selže.

Alternativním řešením pro omezení SQLite je ruční zápis kódu migrace, který provede opětovné sestavení tabulky, když se něco v tabulce změní. Kód přechází do Up migrace a Down metody a zahrnuje:

  • Vytvoření nové tabulky
  • Kopírování dat ze staré tabulky do nové tabulky
  • Přehození staré tabulky.
  • Přejmenování nové tabulky

Psaní kódu specifického pro databázi tohoto typu je mimo rozsah tohoto kurzu. Místo toho tento kurz zahodí a znovu vytvoří databázi pokaždé, když se pokusíte použít migraci, selžou. Další informace naleznete v následujících zdrojích:

Vyřazení databáze

K odstranění databáze použijte SQL Server Průzkumník objektů (SSOX) nebo v konzole Správce balíčků (PMC) spusťte následující příkaz:

Drop-Database

Vytvoření počáteční migrace

V PMC spusťte následující příkazy:

Add-Migration InitialCreate
Update-Database

Odebrání funkce EnsureCreated

Tato série kurzů začala pomocí .EnsureCreated EnsureCreated nevytvoří tabulku historie migrací, takže se nedá použít s migracemi. Je navržená pro testování nebo rychlé vytváření prototypů, kdy se databáze často ukončuje a znovu vytváří.

Od tohoto okamžiku budou kurzy používat migrace.

V Program.cspříkazu odstraňte následující řádek:

context.Database.EnsureCreated();

Spusťte aplikaci a ověřte, že se databáze zasadí.

Metody nahoru a dolů

Příkaz EF Coremigrations add vygeneroval kód pro vytvoření databáze. Tento kód migrace je v Migrations\<timestamp>_InitialCreate.cs souboru. Up Metoda InitialCreate třídy vytvoří databázové tabulky, které odpovídají sadám entit datového modelu. Metoda Down je odstraní, jak je znázorněno v následujícím příkladu:

using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;

namespace ContosoUniversity.Migrations
{
    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Course",
                columns: table => new
                {
                    CourseID = table.Column<int>(nullable: false),
                    Title = table.Column<string>(nullable: true),
                    Credits = table.Column<int>(nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Course", x => x.CourseID);
                });

            migrationBuilder.CreateTable(
                name: "Student",
                columns: table => new
                {
                    ID = table.Column<int>(nullable: false)
                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                    LastName = table.Column<string>(nullable: true),
                    FirstMidName = table.Column<string>(nullable: true),
                    EnrollmentDate = table.Column<DateTime>(nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Student", x => x.ID);
                });

            migrationBuilder.CreateTable(
                name: "Enrollment",
                columns: table => new
                {
                    EnrollmentID = table.Column<int>(nullable: false)
                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                    CourseID = table.Column<int>(nullable: false),
                    StudentID = table.Column<int>(nullable: false),
                    Grade = table.Column<int>(nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Enrollment", x => x.EnrollmentID);
                    table.ForeignKey(
                        name: "FK_Enrollment_Course_CourseID",
                        column: x => x.CourseID,
                        principalTable: "Course",
                        principalColumn: "CourseID",
                        onDelete: ReferentialAction.Cascade);
                    table.ForeignKey(
                        name: "FK_Enrollment_Student_StudentID",
                        column: x => x.StudentID,
                        principalTable: "Student",
                        principalColumn: "ID",
                        onDelete: ReferentialAction.Cascade);
                });

            migrationBuilder.CreateIndex(
                name: "IX_Enrollment_CourseID",
                table: "Enrollment",
                column: "CourseID");

            migrationBuilder.CreateIndex(
                name: "IX_Enrollment_StudentID",
                table: "Enrollment",
                column: "StudentID");
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Enrollment");

            migrationBuilder.DropTable(
                name: "Course");

            migrationBuilder.DropTable(
                name: "Student");
        }
    }
}

Předchozí kód je určený pro počáteční migraci. Kód:

  • Vygeneroval ho migrations add InitialCreate příkaz.
  • Spustí se příkazem database update .
  • Vytvoří databázi pro datový model určený třídou kontextu databáze.

Parametr názvu migrace (InitialCreate v příkladu) se používá pro název souboru. Název migrace může být libovolný platný název souboru. Nejlepší je zvolit slovo nebo frázi, které shrnuje, co se provádí v migraci. Například migrace, která přidala tabulku oddělení, se může jmenovat AddDepartmentTable.

Tabulka historie migrací

  • Ke kontrole databáze použijte nástroj SSOX nebo SQLite.
  • Všimněte si přidání __EFMigrationsHistory tabulky. Tabulka __EFMigrationsHistory sleduje, které migrace se u databáze použily.
  • Umožňuje zobrazit data v __EFMigrationsHistory tabulce. Zobrazuje jeden řádek pro první migraci.

Snímek datového modelu

Migrace vytvoří snímek aktuálního datového modelu v Migrations/SchoolContextModelSnapshot.cssouboru . Když přidáte migraci, EF určí, co se změnilo porovnáním aktuálního datového modelu se souborem snímku.

Vzhledem k tomu, že soubor snímku sleduje stav datového modelu, nelze migraci odstranit odstraněním <timestamp>_<migrationname>.cs souboru. Pokud chcete vrátit zpět nejnovější migraci, použijte migrations remove příkaz. migrations remove odstraní migraci a zajistí, že se snímek správně resetuje. Další informace naleznete v tématu dotnet ef migrations remove.

Pokud chcete odebrat všechny migrace, přečtěte si téma Resetování všech migrací .

Použití migrací v produkčním prostředí

Doporučujeme, aby produkční aplikace při spuštění aplikace volaly Database.Migrate . Migrate aplikace, která je nasazená do serverové farmy, by se neměla volat. Pokud je aplikace škálovaná na více instancí serveru, je obtížné zajistit, aby aktualizace schématu databáze neproběhly z více serverů nebo byly v konfliktu s přístupem pro čtení a zápis.

Migrace databáze by se měla provádět jako součást nasazení a řízeným způsobem. Přístupy k migraci produkční databáze zahrnují:

  • Použití migrací k vytvoření skriptů SQL a použití skriptů SQL v nasazení.
  • Běží dotnet ef database update z řízeného prostředí.

Řešení problému

Pokud aplikace používá SQL Server LocalDB a zobrazí následující výjimku:

SqlException: Cannot open database "ContosoUniversity" requested by the login.
The login failed.
Login failed for user 'user name'.

Řešením může být spuštění dotnet ef database update na příkazovém řádku.

Další materiály

Další kroky

Další kurz sestaví datový model a přidá vlastnosti entity a nové entity.

V tomto kurzu EF Core se používá funkce migrace pro správu změn datového modelu.

Pokud narazíte na problémy, které nemůžete vyřešit, stáhněte si dokončenou aplikaci.

Při vývoji nové aplikace se datový model často mění. Pokaždé, když se model změní, se model nesynchronizuje s databází. Tento kurz začal konfigurací entity Framework pro vytvoření databáze, pokud neexistuje. Pokaždé, když se datový model změní:

  • Databáze se zahodí.
  • EF vytvoří nový, který odpovídá modelu.
  • Aplikace zasadí databázi s testovacími daty.

Tento přístup k udržování databáze v synchronizaci s datovým modelem funguje dobře, dokud nebude potřeba aplikaci nasadit do produkčního prostředí. Když je aplikace spuštěná v produkčním prostředí, obvykle ukládá data, která je potřeba udržovat. Aplikace nemůže začít s testovací databází při každé změně (například přidáním nového sloupce). Funkce EF Core Migrace tento problém řeší povolením EF Core aktualizace schématu databáze místo vytvoření nové databáze.

Místo vyřazení a opětovného vytvoření databáze při změně datového modelu migrace aktualizuje schéma a zachová existující data.

Vyřazení databáze

Použijte SQL Server Průzkumník objektů (SSOX) nebo database drop příkaz:

V konzole Správce balíčků (PMC) spusťte následující příkaz:

Drop-Database

Spuštěním Get-Help about_EntityFrameworkCore z PMC získejte informace o nápovědě.

Vytvoření počáteční migrace a aktualizace databáze

Sestavte projekt a vytvořte první migraci.

Add-Migration InitialCreate
Update-Database

Prozkoumání metod Nahoru a Dolů

Příkaz EF Coremigrations add vygeneroval kód pro vytvoření databáze. Tento kód migrace je v Migrations\<timestamp>_InitialCreate.cs souboru. Up Metoda InitialCreate třídy vytvoří databázové tabulky, které odpovídají sadám entit datového modelu. Metoda Down je odstraní, jak je znázorněno v následujícím příkladu:

public partial class InitialCreate : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Course",
            columns: table => new
            {
                CourseID = table.Column<int>(nullable: false),
                Title = table.Column<string>(nullable: true),
                Credits = table.Column<int>(nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Course", x => x.CourseID);
            });

        migrationBuilder.CreateTable(
    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(
            name: "Enrollment");

        migrationBuilder.DropTable(
            name: "Course");

        migrationBuilder.DropTable(
            name: "Student");
    }
}

Migrace volá metodu Up pro implementaci změn datového modelu pro migraci. Když zadáte příkaz pro vrácení aktualizace zpět, migrace volá metodu Down .

Předchozí kód je určený pro počáteční migraci. Tento kód byl vytvořen při migrations add InitialCreate spuštění příkazu. Parametr názvu migrace (v příkladu InitialCreate) se používá pro název souboru. Název migrace může být libovolný platný název souboru. Nejlepší je zvolit slovo nebo frázi, které shrnuje, co se provádí v migraci. Například migrace, která přidala tabulku oddělení, se může jmenovat AddDepartmentTable.

Pokud se vytvoří počáteční migrace a databáze existuje:

  • Vygeneruje se kód pro vytvoření databáze.
  • Kód pro vytvoření databáze se nemusí spouštět, protože databáze už odpovídá datovému modelu. Pokud je kód pro vytvoření databáze spuštěný, neprovádí žádné změny, protože databáze už odpovídá datovému modelu.

Po nasazení aplikace do nového prostředí musí být kód pro vytvoření databáze spuštěn, aby se vytvořila databáze.

Dříve došlo k vyřazení databáze a neexistuje, takže migrace vytvoří novou databázi.

Snímek datového modelu

Migrace vytvoří snímek aktuálního schématu databáze v Migrations/SchoolContextModelSnapshot.cssouboru . Když přidáte migraci, EF určí, co se změnilo porovnáním datového modelu se souborem snímku.

Pokud chcete migraci odstranit, použijte následující příkaz:

Odebrání migrace

Příkaz pro odebrání migrace odstraní migraci a zajistí, že se snímek správně resetuje.

Odebrání funkce EnsureCreated a otestování aplikace

Pro raný vývoj EnsureCreated byl použit. V tomto kurzu se používají migrace. EnsureCreated má následující omezení:

  • Obchází migrace a vytvoří databázi a schéma.
  • Nevytvoří tabulku migrací.
  • Nejde použít s migracemi.
  • Je navržená pro testování nebo rychlé vytváření prototypů, kdy se databáze často ukončuje a znovu vytváří.

Odebrat EnsureCreated:

context.Database.EnsureCreated();

Spusťte aplikaci a ověřte, že je databáze počáteční.

Kontrola databáze

Ke kontrole databáze použijte sql Server Průzkumník objektů. Všimněte si přidání __EFMigrationsHistory tabulky. Tabulka __EFMigrationsHistory sleduje, které migrace se na databázi použily. Zobrazte data v __EFMigrationsHistory tabulce, zobrazí se jeden řádek pro první migraci. Poslední protokol v předchozím příkladu výstupu rozhraní příkazového řádku ukazuje příkaz INSERT, který vytvoří tento řádek.

Spusťte aplikaci a ověřte, že všechno funguje.

Použití migrací v produkčním prostředí

Doporučujeme, aby produkční aplikace při spuštění aplikace volaly Database.Migrate . Migrate by se nemělo volat z aplikace v serverové farmě. Pokud je například aplikace nasazená v cloudu se škálováním na více instancí (běží více instancí aplikace).

Migrace databáze by se měla provádět jako součást nasazení a řízeným způsobem. Přístupy k migraci produkční databáze zahrnují:

  • Použití migrací k vytvoření skriptů SQL a použití skriptů SQL v nasazení.
  • Běží dotnet ef database update z řízeného prostředí.

EF Core__MigrationsHistory pomocí tabulky zjistí, jestli je potřeba spustit nějaké migrace. Pokud je databáze aktuální, neběží žádná migrace.

Řešení problému

Stáhněte si dokončenou aplikaci.

Aplikace vygeneruje následující výjimku:

SqlException: Cannot open database "ContosoUniversity" requested by the login.
The login failed.
Login failed for user 'user name'.

Řešení: Spusťte dotnet ef database update

Další materiály