Criação de DbContext no tempo de design

Alguns dos comandos EF Core Tools (por exemplo, os comandos de Migrações ) exigem que uma instância derivada DbContext seja criada no momento do design para coletar detalhes sobre os tipos de entidade do aplicativo e como eles são mapeados para um esquema de banco de dados. Na maioria dos casos, é desejável que o DbContext criado seja configurado de maneira semelhante à forma como ele seria configurado em tempo de execução.

Há várias maneiras pelas quais as ferramentas tentam criar:DbContext

De serviços de aplicativo

Se o projeto de inicialização usar o ASP.NET Core Host Web ou o Host Genérico do .NET Core, as ferramentas tentarão obter o objeto DbContext do provedor de serviços do aplicativo.

As ferramentas primeiro tentam obter o provedor de serviços invocando Program.CreateHostBuilder(), chamando Build()e acessando a Services propriedade.

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)
    {
    }
}

Observação

Quando você cria um novo aplicativo ASP.NET Core, esse gancho é incluído por padrão.

As DbContext dependências em si e quaisquer dependências em seu construtor precisam ser registradas como serviços no provedor de serviços do aplicativo. Isso pode ser facilmente alcançado tendo um construtor no DbContext que usa uma instância como DbContextOptions<TContext> argumento e usando o AddDbContext<TContext> método.

Usando um construtor sem parâmetros

Se o DbContext não puder ser obtido do provedor de serviços de aplicativo, as ferramentas procurarão o tipo derivado DbContext dentro do projeto. Em seguida, eles tentam criar uma instância usando um construtor sem parâmetros. Esse pode ser o construtor padrão se ele DbContext estiver configurado usando o OnConfiguring método.

De uma fábrica de tempo de design

Você também pode informar às ferramentas como criar seu DbContext implementando a Microsoft.EntityFrameworkCore.Design.IDesignTimeDbContextFactory<TContext> interface: se uma classe que implementa essa interface for encontrada no mesmo projeto que o derivado DbContext ou no projeto de inicialização do aplicativo, as ferramentas ignorarão as outras maneiras de criar o DbContext e usarão a fábrica de tempo de design.

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

Observação

Antes do EFCore 5.0, o args parâmetro não era usado (consulte esse problema). Isso é corrigido no EFCore 5.0 e quaisquer argumentos adicionais de tempo de design são passados para o aplicativo por meio desse parâmetro.

Uma fábrica de tempo de design pode ser especialmente útil se você precisar configurar de forma diferente para o DbContext tempo de design do que em tempo de execução, se o DbContext construtor usar parâmetros adicionais não estiver registrado em DI, se você não estiver usando DI, ou se, por algum motivo, preferir não ter um CreateHostBuilder método na classe do Main aplicativo ASP.NET Core.

Args

Aceitar IDesignTimeDbContextFactory<TContext>.CreateDbContext argumentos de linha de comando e Program.CreateHostBuilder aceitar.

A partir do EF Core 5.0, você pode especificar esses argumentos das ferramentas:

dotnet ef database update -- --environment Production

O -- token direciona dotnet ef para tratar tudo o que se segue como um argumento e não tentar analisá-los como opções. Todos os argumentos extras não usados são dotnet ef encaminhados para o aplicativo.