Część 4. Razor Strony z migracjami EF Core w ASP.NET Core

Przez Tom Dykstra, Jon P Smith i Rick Anderson

Aplikacja internetowa Contoso University pokazuje, jak tworzyć Razor aplikacje internetowe stron przy użyciu programu EF Core Visual Studio. Aby uzyskać informacje na temat serii samouczków, zobacz pierwszy samouczek.

Jeśli napotkasz problemy, których nie możesz rozwiązać, pobierz ukończoną aplikację i porównaj ten kod z utworzonymi elementami, wykonując czynności opisane w samouczku.

W tym samouczku przedstawiono EF Core funkcję migracji na potrzeby zarządzania zmianami modelu danych.

Podczas tworzenia nowej aplikacji model danych zmienia się często. Za każdym razem, gdy model zmienia się, model nie jest synchronizowany z bazą danych. Ta seria samouczków została uruchomiona przez skonfigurowanie programu Entity Framework w celu utworzenia bazy danych, jeśli nie istnieje. Za każdym razem, gdy zmienia się model danych, baza danych musi zostać porzucona. Przy następnym uruchomieniu aplikacji wywołanie w celu EnsureCreated ponownego utworzenia bazy danych w celu dopasowania do nowego modelu danych. Następnie DbInitializer klasa jest uruchamiana w celu zainicjowania nowej bazy danych.

Takie podejście do zachowania synchronizacji bazy danych z modelem danych działa dobrze do momentu wdrożenia aplikacji w środowisku produkcyjnym. Gdy aplikacja jest uruchomiona w środowisku produkcyjnym, zwykle przechowuje dane, które muszą być przechowywane. Aplikacja nie może rozpoczynać się od testowej bazy danych za każdym razem, gdy zostanie wprowadzona zmiana (na przykład dodanie nowej kolumny). Funkcja EF Core Migracje rozwiązuje ten problem, umożliwiając EF Core aktualizowanie schematu bazy danych zamiast tworzenia nowej bazy danych.

Zamiast usuwać i ponownie utworzyć bazę danych po zmianie modelu danych, migracje aktualizują schemat i zachowują istniejące dane.

Uwaga

Ograniczenia sqlite

W tym samouczku jest używana funkcja migracji platformy Entity Framework Core tam, gdzie to możliwe. Migracje aktualizują schemat bazy danych w celu dopasowania zmian w modelu danych. Jednak migracje robią tylko rodzaje zmian, które obsługuje aparat bazy danych, a możliwości zmiany schematu SQLite są ograniczone. Na przykład dodawanie kolumny jest obsługiwane, ale usuwanie kolumny nie jest obsługiwane. Jeśli migracja zostanie utworzona w celu usunięcia kolumny, polecenie zakończy się powodzeniem, ef migrations add ale polecenie zakończy się niepowodzeniem ef database update .

Obejściem ograniczeń SQLite jest ręczne napisanie kodu migracji w celu ponownego skompilowania tabeli, gdy coś się zmieni w tabeli. Kod przechodzi do Up metod i Down migracji i obejmuje:

  • Tworzenie nowej tabeli.
  • Kopiowanie danych ze starej tabeli do nowej tabeli.
  • Upuszczanie starej tabeli.
  • Zmiana nazwy nowej tabeli.

Pisanie kodu specyficznego dla bazy danych tego typu wykracza poza zakres tego samouczka. Zamiast tego ten samouczek przerywa i ponownie tworzy bazę danych za każdym razem, gdy próba zastosowania migracji zakończy się niepowodzeniem. Aby uzyskać więcej informacji, zobacz następujące zasoby:

Usuwanie bazy danych

Użyj programu SQL Server Eksplorator obiektów (SSOX), aby usunąć bazę danych, lub uruchom następujące polecenie w konsoli Menedżer pakietów (PMC):

Drop-Database

Tworzenie migracji początkowej

Uruchom następujące polecenia w usłudze PMC:

Add-Migration InitialCreate
Update-Database

Usuń upewnij się, że utworzono

Ta seria samouczków została uruchomiona przy użyciu polecenia EnsureCreated. EnsureCreated nie tworzy tabeli historii migracji, dlatego nie można jej używać z migracjami. Jest ona przeznaczona do testowania lub szybkiego tworzenia prototypów, w których baza danych jest porzucana i często tworzona.

Od tego momentu samouczki będą korzystać z migracji.

W Program.cspliku usuń następujący wiersz:

context.Database.EnsureCreated();

Uruchom aplikację i sprawdź, czy baza danych jest rozstawiona.

Metody w górę i w dół

Polecenie EF Coremigrations add wygenerowało kod do utworzenia bazy danych. Ten kod migracji znajduje się w Migrations\<timestamp>_InitialCreate.cs pliku . Metoda UpInitialCreate klasy tworzy tabele bazy danych, które odpowiadają zestawom jednostek modelu danych. Metoda Down usuwa je, jak pokazano w poniższym przykładzie:

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");
        }
    }
}

Powyższy kod dotyczy migracji początkowej. Kod:

  • Został wygenerowany przez migrations add InitialCreate polecenie .
  • Jest wykonywany przez database update polecenie .
  • Tworzy bazę danych dla modelu danych określonego przez klasę kontekstu bazy danych.

Parametr nazwy migracji (InitialCreate w przykładzie) jest używany dla nazwy pliku. Nazwa migracji może być dowolną prawidłową nazwą pliku. Najlepiej wybrać słowo lub frazę podsumowującą czynności wykonywane w migracji. Na przykład migracja, która dodała tabelę działów, może mieć nazwę "AddDepartmentTable".

Tabela historii migracji

  • Użyj narzędzia SSOX lub SQLite, aby sprawdzić bazę danych.
  • Zwróć uwagę na dodanie __EFMigrationsHistory tabeli. Tabela __EFMigrationsHistory śledzi, które migracje zostały zastosowane do bazy danych.
  • Wyświetl dane w __EFMigrationsHistory tabeli. Przedstawia jeden wiersz dla pierwszej migracji.

Migawka modelu danych

Migracje tworzy migawkę bieżącego modelu danych w programie Migrations/SchoolContextModelSnapshot.cs. Po dodaniu migracji program EF określa, co zmieniło się, porównując bieżący model danych z plikiem migawki.

Ponieważ plik migawki śledzi stan modelu danych, nie można usunąć migracji przez usunięcie <timestamp>_<migrationname>.cs pliku. Aby wycofać najnowszą migrację migrations remove , użyj polecenia . migrations remove Usuwa migrację i gwarantuje, że migawka zostanie poprawnie zresetowana. Aby uzyskać więcej informacji, zobacz dotnet ef migrations remove (Usuwanie migracji platformy dotnet ef).

Zobacz Resetowanie wszystkich migracji, aby usunąć wszystkie migracje .

Stosowanie migracji w środowisku produkcyjnym

Zalecamy, aby aplikacje produkcyjne nie wywoływać elementu Database.Migrate podczas uruchamiania aplikacji. Migrate nie należy wywoływać z aplikacji wdrożonej w farmie serwerów. Jeśli aplikacja jest skalowana w poziomie do wielu wystąpień serwera, trudno jest upewnić się, że aktualizacje schematu bazy danych nie są wykonywane z wielu serwerów ani nie powodują konfliktu z dostępem do odczytu/zapisu.

Migracja bazy danych powinna odbywać się w ramach wdrażania i w kontrolowany sposób. Metody migracji produkcyjnej bazy danych obejmują:

  • Używanie migracji do tworzenia skryptów SQL i używania skryptów SQL we wdrożeniu.
  • Uruchamianie dotnet ef database update z kontrolowanego środowiska.

Rozwiązywanie problemów

Jeśli aplikacja używa bazy danych SQL Server LocalDB i wyświetla następujący wyjątek:

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

Rozwiązaniem może być uruchomienie dotnet ef database update w wierszu polecenia.

Dodatkowe zasoby

Następne kroki

W następnym samouczku zostanie utworzony model danych, dodając właściwości jednostki i nowe jednostki.

W tym samouczku EF Core jest używana funkcja migracji do zarządzania zmianami modelu danych.

Jeśli napotkasz problemy, których nie możesz rozwiązać, pobierz ukończoną aplikację.

Podczas tworzenia nowej aplikacji model danych zmienia się często. Za każdym razem, gdy model zmienia się, model nie jest synchronizowany z bazą danych. W tym samouczku rozpoczęto konfigurowanie programu Entity Framework w celu utworzenia bazy danych, jeśli nie istnieje. Za każdym razem, gdy zmienia się model danych:

  • Baza danych została porzucona.
  • Program EF tworzy nowy, który jest zgodny z modelem.
  • Aplikacja wysiewuje bazę danych z danymi testowymi.

Takie podejście do zachowania synchronizacji bazy danych z modelem danych działa dobrze do momentu wdrożenia aplikacji w środowisku produkcyjnym. Gdy aplikacja jest uruchomiona w środowisku produkcyjnym, zwykle przechowuje dane, które muszą być przechowywane. Aplikacja nie może rozpoczynać się od testowej bazy danych za każdym razem, gdy zostanie wprowadzona zmiana (na przykład dodanie nowej kolumny). Funkcja EF Core Migracje rozwiązuje ten problem, umożliwiając EF Core aktualizowanie schematu bazy danych zamiast tworzenia nowej bazy danych.

Zamiast usuwać i ponownie utworzyć bazę danych po zmianie modelu danych, migracje aktualizują schemat i zachowują istniejące dane.

Usuwanie bazy danych

Użyj Eksplorator obiektów programu SQL Server (SSOX) lub database drop polecenia:

W konsoli Menedżer pakietów (PMC) uruchom następujące polecenie:

Drop-Database

Uruchom polecenie Get-Help about_EntityFrameworkCore z pmC, aby uzyskać informacje pomocy.

Tworzenie początkowej migracji i aktualizowanie bazy danych

Skompiluj projekt i utwórz pierwszą migrację.

Add-Migration InitialCreate
Update-Database

Badanie metod w górę i w dół

Polecenie EF Coremigrations add wygenerowało kod do utworzenia bazy danych. Ten kod migracji znajduje się w Migrations\<timestamp>_InitialCreate.cs pliku . Metoda UpInitialCreate klasy tworzy tabele bazy danych, które odpowiadają zestawom jednostek modelu danych. Metoda Down usuwa je, jak pokazano w poniższym przykładzie:

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");
    }
}

Migracje wywołuje metodę Up implementowania zmian modelu danych na potrzeby migracji. Po wprowadzeniu polecenia w celu wycofania aktualizacji migracje wywołuje metodę Down .

Powyższy kod dotyczy migracji początkowej. Ten kod został utworzony podczas uruchamiania migrations add InitialCreate polecenia. Parametr nazwy migracji ("InitialCreate" w przykładzie) jest używany dla nazwy pliku. Nazwa migracji może być dowolną prawidłową nazwą pliku. Najlepiej wybrać słowo lub frazę podsumowującą czynności wykonywane w migracji. Na przykład migracja, która dodała tabelę działów, może mieć nazwę "AddDepartmentTable".

Jeśli migracja początkowa zostanie utworzona, a baza danych istnieje:

  • Zostanie wygenerowany kod tworzenia bazy danych.
  • Kod tworzenia bazy danych nie musi być uruchamiany, ponieważ baza danych jest już zgodna z modelem danych. Jeśli kod tworzenia bazy danych jest uruchamiany, nie wprowadza żadnych zmian, ponieważ baza danych jest już zgodna z modelem danych.

Po wdrożeniu aplikacji w nowym środowisku należy uruchomić kod tworzenia bazy danych, aby utworzyć bazę danych.

Wcześniej baza danych została porzucona i nie istnieje, więc migracje tworzą nową bazę danych.

Migawka modelu danych

Migracje tworzą migawkę bieżącego schematu bazy danych w programie Migrations/SchoolContextModelSnapshot.cs. Podczas dodawania migracji program EF określa, co zmieniło się, porównując model danych z plikiem migawek.

Aby usunąć migrację, użyj następującego polecenia:

Usuwanie migracji

Polecenie remove migrations usuwa migrację i gwarantuje, że migawka zostanie poprawnie zresetowana.

Usuń pozycję Upewnij się, że utworzono i przetestuj aplikację

Do wczesnego opracowywania EnsureCreated użyto. W tym samouczku są używane migracje. EnsureCreated ma następujące ograniczenia:

  • Pomija migracje i tworzy bazę danych i schemat.
  • Nie tworzy tabeli migracji.
  • Nie można używać z migracjami.
  • Jest przeznaczony do testowania lub szybkiego tworzenia prototypów, w których baza danych jest porzucana i często tworzona.

Usuń EnsureCreated:

context.Database.EnsureCreated();

Uruchom aplikację i sprawdź, czy baza danych jest rozmieszczana.

Inspekcja bazy danych

Użyj Eksplorator obiektów programu SQL Server, aby sprawdzić bazę danych. Zwróć uwagę na dodanie __EFMigrationsHistory tabeli. Tabela __EFMigrationsHistory śledzi, które migracje zostały zastosowane do bazy danych. Wyświetl dane w __EFMigrationsHistory tabeli. Zawiera on jeden wiersz dla pierwszej migracji. Ostatni dziennik w poprzednim przykładzie danych wyjściowych interfejsu wiersza polecenia przedstawia instrukcję INSERT, która tworzy ten wiersz.

Uruchom aplikację i sprawdź, czy wszystko działa.

Stosowanie migracji w środowisku produkcyjnym

Zalecamy, aby aplikacje produkcyjne nie powinny wywoływać elementu Database.Migrate podczas uruchamiania aplikacji. Migrate nie powinna być wywoływana z aplikacji w farmie serwerów. Jeśli na przykład aplikacja została wdrożona w chmurze z skalowaniem w poziomie (uruchomiono wiele wystąpień aplikacji).

Migracja bazy danych powinna odbywać się w ramach wdrażania i w kontrolowany sposób. Metody migracji produkcyjnej bazy danych obejmują:

  • Używanie migracji do tworzenia skryptów SQL i używania skryptów SQL we wdrożeniu.
  • Uruchamianie dotnet ef database update z kontrolowanego środowiska.

EF Core__MigrationsHistory używa tabeli , aby sprawdzić, czy należy uruchomić jakiekolwiek migracje. Jeśli baza danych jest aktualna, nie zostanie uruchomiona żadna migracja.

Rozwiązywanie problemów

Pobierz ukończoną aplikację.

Aplikacja generuje następujący wyjątek:

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

Rozwiązanie: Uruchamianie dotnet ef database update

Dodatkowe zasoby