EF Core - Criação do DbContext em tempo de projeto


 Hoje veremos como criar o DbContext em tempo de projeto em aplicações ASP .NET Core.

Alguns dos comandos EF Core Tools (por exemplo, os comandos Migrations) exigem que uma instância DbContext derivada seja criada em tempo de projeto para reunir 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 assim criado seja configurado de forma semelhante a como seria configurado em tempo de execução.

Existem diversas formas das ferramentas criarem o DbContext.

1- A partir dos serviços da aplicação

Se o seu projeto startup usa o ASP.NET Core Web Host ou o .NET Core Generic Host, as ferramentas tentam obter o objeto DbContext do provedor de serviços do aplicativo.

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

public class Program
{
    public static void Main(string[] args)
        => CreateHostBuilder(args).Build().Run();
    // EF Core usa este método em tempo de projeto para acessar o DbContext
    public static IHostBuilder CreateHostBuilder(string[] args)
        => Host.CreateDefaultBuilder(args)
                 .ConfigureWebHostDefaults(
                     webBuilder => webBuilder.UseStartup<Startup>());
}
- Método ConfigureServices no Startup:
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
        => services.AddDbContext<ApplicationDbContext>();
}
- Arquivo de contexto:
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}

O próprio DbContext e quaisquer dependências em seu construtor precisam ser registrados como serviços no provedor de serviços do aplicativo.

Isso pode ser facilmente alcançado tendo um construtor no DbContext que leva uma instância de DbContextOptions<TContext> como um argumento e usando o método AddDbContext<TContext>.

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

2- A partir uma factory em tempo de projeto

Você também pode dizer às ferramentas como criar seu DbContext implementando a interface IDesignTimeDbContextFactory<TContext>

Se uma classe que implementa esta interface for encontrada no mesmo projeto que o DbContext derivado ou no projeto de inicialização do aplicativo, as ferramentas contornam as outras maneiras de criar o DbContext e usam a fábrica em tempo de projeto no seu lugar.

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace DemoProject
{
    public class DemoContextFactory : IDesignTimeDbContextFactory<DemoContext>
    {
        public DemoContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<DemoContext>();
            optionsBuilder.UseSqlite("Data Source=blog.db");
            return new DemoContext(optionsBuilder.Options);
        }
    }
}

Usar uma fábrica em tempo de projeto pode ser especialmente útil se :

  1. Você precisar configurar o DbContext de forma diferente para o tempo de projeto do tempo de execução;

  2. Se o construtor DbContext tomar parâmetros adicionais não registrados no DI;

  3. Se você não estiver usando o contêiner de injeção de dependência nativo (DI);

  4. Se for algum motivo você prefere não ter um método BuildWebHost na classe Main do aplicativo ASP.NET Core;

Por isso fique atento a este recurso quando for criar uma solução ASP .NET Core com diversos projetos e precisar criar o Migrations em um projeto referenciando o EF Core.

E estamos conversados...

"E percorria Jesus todas as cidades e aldeias, ensinando nas sinagogas deles, e pregando o evangelho do reino, e curando todas as enfermidades e moléstias entre o povo."
Mateus 9:35

Referências:


José Carlos Macoratti