Creación de DbContext en tiempo de diseño

Algunos de los comandos de EF Core Tools (por ejemplo, los comandos Migrations ) requieren que se cree una instancia derivada DbContext en tiempo de diseño para recopilar detalles sobre los tipos de entidad de la aplicación y cómo se asignan a un esquema de base de datos. En la mayoría de los casos, es deseable que el DbContext objeto creado se configure de forma similar a cómo se configuraría en tiempo de ejecución.

Hay varias formas en que las herramientas intentan crear el DbContext:

Servicios de aplicación

Si el proyecto de inicio usa el host web de ASP.NET Core o el host genéricode .NET Core, las herramientas intentan obtener el objeto DbContext del proveedor de servicios de la aplicación.

Las herramientas intentan obtener primero el proveedor de servicios invocando Program.CreateHostBuilder(), llamando a Build() y accediendo a la propiedad Services.

public class Program
{
    public static void Main(string[] args)
        => CreateHostBuilder(args).Build().Run();

    // EF Core uses this method at design time to access the DbContext
    public static IHostBuilder CreateHostBuilder(string[] args)
        => Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(
                webBuilder => webBuilder.UseStartup<Startup>());
}

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
        => services.AddDbContext<ApplicationDbContext>();

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
    }
}

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}

Nota:

Al crear una nueva aplicación ASP.NET Core, este enlace se incluye de forma predeterminada.

El propio DbContext y las dependencias de su constructor deben registrarse como servicios en el proveedor de servicios de la aplicación. Esto se puede lograr fácilmente teniendo un constructor en que DbContext toma una instancia de DbContextOptions<TContext> como argumento y usando el AddDbContext<TContext> método.

Uso de un constructor sin parámetros

Si DbContext no se puede obtener del proveedor de servicios de aplicación, las herramientas buscan el tipo derivado DbContext dentro del proyecto. A continuación, intentan crear una instancia mediante un constructor sin parámetros. Puede ser el constructor predeterminado si DbContext está configurado mediante el método OnConfiguring.

Desde una fábrica en tiempo de diseño

También puede indicar a las herramientas cómo crear dbContext mediante la implementación de la Microsoft.EntityFrameworkCore.Design.IDesignTimeDbContextFactory<TContext> interfaz: si se encuentra una clase que implementa esta interfaz en el mismo proyecto que el derivado DbContext o en el proyecto de inicio de la aplicación, las herramientas omiten las otras formas de crear DbContext y usan el generador en tiempo de diseño en su lugar.

public class BloggingContextFactory : IDesignTimeDbContextFactory<BloggingContext>
{
    public BloggingContext CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
        optionsBuilder.UseSqlite("Data Source=blog.db");

        return new BloggingContext(optionsBuilder.Options);
    }
}

Un generador en tiempo de diseño puede ser especialmente útil si necesita configurar de forma diferente para el DbContext tiempo de diseño que en tiempo de ejecución, si el DbContext constructor toma parámetros adicionales no están registrados en la inserción de dependencias, si no usa di en absoluto, o si por algún motivo prefiere no tener un CreateHostBuilder método en la clase de Main la aplicación ASP.NET Core.

Args

Tanto IDesignTimeDbContextFactory<TContext>.CreateDbContext como Program.CreateHostBuilder aceptan argumentos de línea de comandos.

Puede especificar estos argumentos desde las herramientas:

dotnet ef database update -- --environment Production

El -- token dirige dotnet ef a tratar todo lo que sigue como argumento y no intenta analizarlos como opciones. Los argumentos adicionales no utilizados por dotnet ef se reenvieron a la aplicación.