creare automaticamente il database in Entity Framework Core


100

La mia applicazione che viene portata su .NET core utilizzerà il nuovo EF Core con SQLite. Voglio creare automaticamente il database e le strutture delle tabelle quando l'app viene eseguita per la prima volta. Secondo la documentazione di base EF, questo viene fatto utilizzando i comandi manuali

dotnet ef migrations add MyFirstMigration

dotnet ef database update

Tuttavia, non voglio che l'utente finale inserisca questi comandi e preferirei che l'app crei e configuri il database per il primo utilizzo. Per EF 6 sono disponibili funzionalità come

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

Ma in EF Core questi non sembrano esistere. Non riesco a trovare alcun esempio o documentazione su qualcosa di equivalente per EF core e non è menzionato nell'elenco delle funzionalità mancanti nella documentazione EF core. Ho già impostato le classi del modello in modo da poter scrivere del codice per inizializzare il database in base ai modelli, ma sarebbe molto più semplice se il framework lo facesse automaticamente. Non voglio costruire automaticamente il modello o migrare, basta creare le strutture delle tabelle su un nuovo database.

Mi manca qualcosa qui o la funzione di creazione automatica della tabella manca nel core EF?

Risposte:


146

Se hai creato le migrazioni, puoi eseguirle in Startup.cs come segue.

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

      ...

Questo creerà il database e le tabelle utilizzando le migrazioni aggiunte.

Se non usi Entity Framework Migrations e invece hai solo bisogno del tuo modello DbContext creato esattamente come è nella tua classe di contesto alla prima esecuzione, puoi usare:

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

      ...

Anziché.

Se devi eliminare il database prima di assicurarti che sia stato creato, chiama:

            context.Database.EnsureDeleted();

Appena prima di chiamare EnsureCreated()

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


1
Sono ancora abbastanza nuovo in EF, ho creato le classi che definiscono le strutture di dati utilizzando prima il codice EF 6 "crea da database" da Visual Studio utilizzando un file di database corrente. Quindi li ho tagliati / incollati nella nuova soluzione VS dotnet core, quindi immagino che non si tratti di migrazioni. Ciò significa che devo creare un file di migrazione prima che il codice sopra possa essere utilizzato?
Deandob

2
Mi dispiace, ho fatto un errore nella mia risposta, se non stai usando le migrazioni, puoi usare il comando context.Database.EnsureCreated () / GuaranteDeleted (), maggiori dettagli in blogs.msdn.microsoft.com/dotnet/2016 / 09/29 /…
Ricardo Fontana

2
E se avessi bisogno di entrambe le soluzioni? Abbiamo appena portato la nostra app su UWP e iniziato a usare EF Core, il che significa che alcuni utenti hanno bisogno del DB per essere creato da zero, mentre altri hanno già il DB. C'è un modo per garantire che la prima migrazione crei solo le tabelle iniziali se non esistono già? La tua risposta non sembra coprire questo o mi manca qualcosa?
Lars Udengaard

33

La mia risposta è molto simile alla risposta di Ricardo, ma sento che il mio approccio è un po 'più diretto semplicemente perché c'è così tanto da fare nella sua usingfunzione che non sono nemmeno sicuro di come funzioni esattamente a un livello inferiore.

Quindi, per coloro che desiderano una soluzione semplice e pulita che crei un database per te in cui sai esattamente cosa sta succedendo sotto il cofano, questo è per te:

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

Ciò significa praticamente che all'interno del DbContextche hai creato (in questo caso, il mio è chiamato TargetsContext), puoi usare un'istanza di DbContextper assicurarti che le tabelle definite con nella classe vengano create quando Startup.cs viene eseguito nella tua applicazione.


10
Proprio come un'informazione da qui : EnsureCreatedignora totalmente le migrazioni e crea solo lo schema per te, non puoi mescolarlo con le migrazioni. EnsureCreatedè progettato per il test o la prototipazione rapida in cui è possibile eliminare e ricreare il database ogni volta. Se stai utilizzando le migrazioni e desideri che vengano applicate automaticamente all'avvio dell'app, puoi utilizzarle context.Database.Migrate().
Thomas Schneiter

Questo risponde alla mia confusione sul perché la mia stringa di connessione non funziona ... :( Quindi il database non è stato creato automaticamente che devi specificare Database.EnsureCreated () che ho fatto nel mio costruttore DbContext. Grazie mille, mi salva dal dilemma di 3 giorni. X_X
pampi

Volevo solo notare che ho appena provato a incollarlo nel mio file di avvio e VS2019 mi ha informato che IHostingEnvironmentora è deprecato e l'alternativa consigliata è Microsoft.AspNetCore.Hosting.IWebHostEnvironment.
ctrl-z pls

18

Se ottieni il contesto tramite l'elenco dei parametri di Configure in Startup.cs, puoi invece farlo:

public void Configure(IApplicationBuilder app, IHostingEnvironment env,  LoggerFactory loggerFactory,
    ApplicationDbContext context)
 {
      context.Database.Migrate();
      ...

1
IMHO questa è la soluzione migliore: non devi preoccuparti di nessun servizio o anche del contesto DB, puoi semplicemente usare il contesto che ottieni tramite l'iniezione di dipendenza. Bello!
Tobias

12

Per EF Core 2.0+ ho dovuto adottare un approccio diverso perché hanno cambiato l'API. A partire da marzo 2019 Microsoft consiglia di inserire il codice di migrazione del database nella classe di ingresso dell'applicazione ma al di fuori del codice di compilazione 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>();
}

7

Se non hai creato le migrazioni, ci sono 2 opzioni

1.crea il database e le tabelle dall'applicazione Main:

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

2.crea le tabelle se il database esiste già:

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

Grazie alla risposta di Bubi


2
quali sono i tuoi servizi?
MichaelMao

Tutta la documentazione che sto leggendo mostra grossi avvertimenti sulle migrazioni che dicono "Non usare EnsureCreatedo EnsureDeletedo Database.Migratefalliranno"
mwilson
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.