Čá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.cs
pří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.cs
souboru . 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
- EF Core ROZHRANÍ příkazového řádku.
- dotnet ef migrations CLI – příkazy rozhraní příkazového řádku
- Konzola Správce balíčků (Visual Studio)
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.cs
souboru . 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