crear automáticamente una base de datos en Entity Framework Core

100

Mi aplicación que se está portando a .NET core utilizará el nuevo EF Core con SQLite. Quiero crear automáticamente las estructuras de la base de datos y la tabla cuando la aplicación se ejecuta por primera vez. De acuerdo con la documentación principal de EF, esto se hace usando comandos manuales

dotnet ef migrations add MyFirstMigration

dotnet ef database update

Sin embargo, no quiero que el usuario final ingrese estos comandos y preferiría que la aplicación cree y configure la base de datos para el primer uso. Para EF 6 hay una funcionalidad como

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

Pero en EF Core, estos no parecen existir. No puedo encontrar ningún ejemplo o documentación sobre algo equivalente para el núcleo de EF y no se menciona en la lista de características faltantes en la documentación del núcleo de EF. Ya tengo la configuración de las clases del modelo, así que podría escribir un código para inicializar la base de datos en función de los modelos, pero sería mucho más fácil si el marco lo hiciera automáticamente. No quiero construir automáticamente el modelo o migrar, solo crear las estructuras de la tabla en una nueva base de datos.

¿Me falta algo aquí o falta la función de tabla de creación automática en el núcleo de EF?

deandob
fuente

Respuestas:

146

Si ha creado las migraciones, puede ejecutarlas en Startup.cs de la siguiente manera.

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

      ...

Esto creará la base de datos y las tablas usando sus migraciones agregadas.

Si no está utilizando Entity Framework Migrations y, en su lugar, solo necesita que su modelo DbContext se cree exactamente como está en su clase de contexto en la primera ejecución, puede usar:

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

      ...

En lugar.

Si necesita eliminar su base de datos antes de asegurarse de que esté creada, llame a:

            context.Database.EnsureDeleted();

Justo antes de llamar EnsureCreated()

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

Ricardo Fontana
fuente
1
Todavía soy bastante nuevo en EF, creé las clases que definen las estructuras de datos usando el código EF 6 primero "crear desde la base de datos" desde Visual Studio usando un archivo de base de datos actual. Luego corté / pegué estos en la nueva solución dotnet core VS, así que supongo que no son migraciones. ¿Eso significa que tengo que crear un archivo de migraciones antes de que se pueda usar el código anterior?
deandob
2
Lo siento, cometí un error en mi respuesta, si no está usando migraciones, puede usar el comando context.Database.EnsureCreated () / GuaranteDeleted (), más detalles en blogs.msdn.microsoft.com/dotnet/2016 / 09/29 /…
Ricardo Fontana
2
¿Y si necesita ambas soluciones? Acabamos de migrar nuestra aplicación a UWP y comenzamos a usar EF Core, lo que significa que algunos usuarios necesitan que la base de datos se cree desde cero, mientras que otros ya la tienen. ¿Hay alguna forma de garantizar que la primera migración solo cree las tablas iniciales si aún no existen? ¿Tu respuesta no parece cubrir esto o me falta algo?
Lars Udengaard
33

Mi respuesta es muy similar a la respuesta de Ricardo, pero siento que mi enfoque es un poco más sencillo simplemente porque su usingfunción es tan importante que ni siquiera estoy seguro de cómo funciona exactamente en un nivel inferior.

Entonces, para aquellos que desean una solución simple y limpia que cree una base de datos para usted donde sepa exactamente lo que está sucediendo bajo el capó, esto es para usted:

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

Esto básicamente significa que dentro del DbContextque creó (en este caso, se llama el mío TargetsContext), puede usar una instancia del DbContextpara asegurarse de que las tablas definidas con en la clase se creen cuando Startup.cs se ejecuta en su aplicación.

susieloo_
fuente
10
Solo como información de aquí : EnsureCreatedomite totalmente las migraciones y simplemente crea el esquema para usted, no puede mezclar esto con las migraciones. EnsureCreatedestá diseñado para pruebas o prototipos rápidos en los que está de acuerdo con colocar y volver a crear la base de datos cada vez. Si está utilizando migraciones y desea que se apliquen automáticamente al inicio de la aplicación, puede utilizar context.Database.Migrate()en su lugar.
Thomas Schneiter
Esto responde a mi confusión por qué mi cadena de conexión no funciona ... :( Entonces, la base de datos no se crea automáticamente, debe especificar Database.EnsureCreated (), lo cual hice en mi constructor DbContext. Muchas gracias, me ahorra el dilema de 3 días. X_X
pampi
Solo quería señalar que intenté pegar esto en mi archivo de inicio y VS2019 me informó que IHostingEnvironmentahora está en desuso y que la alternativa recomendada es Microsoft.AspNetCore.Hosting.IWebHostEnvironment.
ctrl-z pls
18

Si obtiene el contexto a través de la lista de parámetros de Configure en Startup.cs, puede hacer esto:

public void Configure(IApplicationBuilder app, IHostingEnvironment env,  LoggerFactory loggerFactory,
    ApplicationDbContext context)
 {
      context.Database.Migrate();
      ...
John Pankowicz
fuente
1
En mi humilde opinión, esta es la mejor solución: no tiene que preocuparse por ningún servicio o incluso el contexto de la base de datos, solo puede usar el contexto que obtiene a través de la inyección de dependencia. ¡Agradable!
Tobias
13

Para EF Core 2.0+ tuve que adoptar un enfoque diferente porque cambiaron la API. A partir de marzo de 2019, Microsoft recomienda que coloque el código de migración de su base de datos en la clase de entrada de su aplicación, pero fuera del código de compilación de 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
fuente
7

Si no ha creado migraciones, hay 2 opciones

1.Cree la base de datos y las tablas desde la aplicación Main:

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

2.crear las tablas si la base de datos ya existe:

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

Gracias a la respuesta de Bubi

Nathan Alard
fuente
2
cuales son sus servicios
MichaelMao
Toda la documentación que estoy leyendo muestra advertencias grandes de grasa alrededor de las migraciones que decían "No utilice EnsureCreatedo EnsureDeletedo Database.Migratese producirá un error"
mwilson