automatyczne tworzenie bazy danych w Entity Framework Core

103

Moja aplikacja, która jest przenoszona do .NET core, będzie używać nowego EF Core z SQLite. Chcę automatycznie utworzyć bazę danych i struktury tabel podczas pierwszego uruchomienia aplikacji. Zgodnie z dokumentacją rdzenia EF odbywa się to za pomocą poleceń ręcznych

dotnet ef migrations add MyFirstMigration

dotnet ef database update

Jednak nie chcę, aby użytkownik końcowy wprowadzał te polecenia i wolałbym, aby aplikacja utworzyła i skonfigurowała bazę danych do pierwszego użycia. Dla EF 6 jest funkcjonalność podobna do

Database.SetInitializer(new CreateDatabaseIfNotExists<MyContext>());

Ale w EF Core wydaje się, że nie istnieją. Nie mogę znaleźć żadnych przykładów ani dokumentacji dotyczącej czegoś równoważnego dla rdzenia EF i nie ma tego na liście brakujących funkcji w dokumentacji rdzenia EF. Mam już skonfigurowane klasy modeli, więc mógłbym napisać kod do zainicjowania bazy danych w oparciu o modele, ale byłoby dużo łatwiej, gdyby framework robił to automatycznie. Nie chcę automatycznie budować modelu ani migrować, po prostu tworzę struktury tabel w nowej bazie danych.

Czy brakuje mi czegoś tutaj lub czy brakuje funkcji automatycznego tworzenia tabeli w rdzeniu EF?

deandob
źródło

Odpowiedzi:

151

Jeśli utworzyłeś migracje, możesz wykonać je w pliku Startup.cs w następujący sposób.

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 {
      using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
      {
            var context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            context.Database.Migrate();
      }

      ...

Spowoduje to utworzenie bazy danych i tabel przy użyciu dodanych migracji.

Jeśli nie używasz migracji Entity Framework, a zamiast tego potrzebujesz modelu DbContext utworzonego dokładnie tak, jak w klasie kontekstu przy pierwszym uruchomieniu, możesz użyć:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 {
      using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
      {
            var context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            context.Database.EnsureCreated();
      }

      ...

Zamiast.

Jeśli chcesz usunąć bazę danych przed upewnieniem się, że została utworzona, zadzwoń:

            context.Database.EnsureDeleted();

Tuż przed telefonem EnsureCreated()

Na podstawie: http://docs.identityserver.io/en/latest/quickstarts/7_entity_framework.html?highlight=entity

Ricardo Fontana
źródło
1
Wciąż jestem całkiem nowy w EF, stworzyłem klasy, które definiują struktury danych przy użyciu kodu EF 6, najpierw „utwórz z bazy danych” z programu Visual Studio przy użyciu bieżącego pliku bazy danych. Następnie wyciąłem / wkleiłem je do nowego rozwiązania VS z rdzeniem dotnet - więc myślę, że to nie są migracje. Czy to oznacza, że ​​muszę utworzyć plik migracji, zanim będzie można użyć powyższego kodu?
deandob
2
Przepraszam, popełniłem błąd w mojej odpowiedzi, jeśli nie korzystasz z migracji, możesz użyć kontekstu polecenia.Database.EnsureCreated () / MakeDeleted (), więcej szczegółów w blogs.msdn.microsoft.com/dotnet/2016 / 09/29 /…
Ricardo Fontana
2
A jeśli potrzebujesz obu rozwiązań? Właśnie przeportowaliśmy naszą aplikację do platformy UWP i zaczęliśmy używać EF Core, co oznacza, że ​​niektórzy użytkownicy potrzebują bazy danych do utworzenia od podstaw, podczas gdy inni już mają bazę danych. Czy istnieje sposób na zapewnienie, że podczas pierwszej migracji tworzone są tabele początkowe tylko wtedy, gdy jeszcze nie istnieją? Twoja odpowiedź nie wydaje się być odpowiedzią na to pytanie lub coś mi brakuje?
Lars Udengaard,
35

Moja odpowiedź jest bardzo podobna do odpowiedzi Ricardo, ale wydaje mi się, że moje podejście jest trochę prostsze, ponieważ w jego usingfunkcji dzieje się tak dużo, że nie jestem nawet pewien, jak dokładnie działa na niższym poziomie.

Więc dla tych, którzy chcą prostego i przejrzystego rozwiązania, które tworzy dla Ciebie bazę danych, w której dokładnie wiesz, co dzieje się pod maską, to jest dla Ciebie:

public Startup(IHostingEnvironment env)
{
    using (var client = new TargetsContext())
    {
        client.Database.EnsureCreated();
    }
}

To prawie oznacza, że ​​w ramach DbContexttego, który utworzyłeś (w tym przypadku nazywa się mój TargetsContext), możesz użyć wystąpienia the, DbContextaby upewnić się, że tabele zdefiniowane w klasie są tworzone, gdy Startup.cs jest uruchamiany w twojej aplikacji.

susieloo_
źródło
11
Tak jak informacja z tego miejsca : EnsureCreatedcałkowicie omija migracje i po prostu tworzy schemat dla Ciebie, nie możesz tego mieszać z migracjami. EnsureCreatedjest przeznaczony do testowania lub szybkiego prototypowania, w którym można za każdym razem upuszczać i ponownie tworzyć bazę danych. Jeśli używasz migracji i chcesz, aby były automatycznie stosowane przy uruchamianiu aplikacji, możesz użyć context.Database.Migrate()zamiast tego.
Thomas Schneiter
Odpowiada to na moje zdezorientowanie, dlaczego moje parametry połączenia nie działają ... :( Więc baza danych nie została utworzona automatycznie, musisz określić Database.EnsureCreated (), co zrobiłem w moim konstruktorze DbContext. Dziękuję bardzo, oszczędza mi dylemat 3 dni. x_X
pampi
Chciałem tylko zauważyć, że właśnie próbowałem wkleić to w moim pliku startowym i VS2019 poinformował mnie, że IHostingEnvironmentjest teraz przestarzały, a zalecaną alternatywą jest Microsoft.AspNetCore.Hosting.IWebHostEnvironment.
ctrl-z pls
18

Jeśli uzyskasz kontekst za pośrednictwem listy parametrów Konfiguruj w Startup.cs, możesz zamiast tego zrobić to:

public void Configure(IApplicationBuilder app, IHostingEnvironment env,  LoggerFactory loggerFactory,
    ApplicationDbContext context)
 {
      context.Database.Migrate();
      ...
John Pankowicz
źródło
1
IMHO to najlepsze rozwiązanie: nie musisz przejmować się żadną usługą ani nawet kontekstem bazy danych, po prostu możesz użyć kontekstu, który otrzymujesz poprzez wstrzyknięcie zależności. Ładny!
Tobias
13

W przypadku EF Core 2.0+ musiałem przyjąć inne podejście, ponieważ zmienili interfejs API. Od marca 2019 r.Microsoft zaleca umieszczenie kodu migracji bazy danych w klasie wejściowej aplikacji, ale poza kodem kompilacji WebHost.

public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateWebHostBuilder(args).Build();
        using (var serviceScope = host.Services.CreateScope())
        {
            var context = serviceScope.ServiceProvider.GetRequiredService<PersonContext>();
            context.Database.Migrate();
        }
        host.Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}
Paul Stegler
źródło
7

Jeśli nie utworzyłeś migracji, są dwie opcje

1. utwórz bazę danych i tabele z aplikacji Main:

var context = services.GetRequiredService<YourRepository>();
context.Database.EnsureCreated();

2. utwórz tabele, jeśli baza danych już istnieje:

var context = services.GetRequiredService<YourRepository>();
context.Database.EnsureCreated();
RelationalDatabaseCreator databaseCreator =
(RelationalDatabaseCreator)context.Database.GetService<IDatabaseCreator>();
databaseCreator.CreateTables();

Dzięki odpowiedzi Bubi

Nathan Alard
źródło
3
jakie są twoje usługi?
MichaelMao
Cała dokumentacja Czytam widać duże ostrzeżenia tłuszczu wokół migracji mówiąc „Nie używać EnsureCreatedlub EnsureDeletedczy Database.Migratenie uda”
mwilson