EF Core - Configurando o DBContext |
Neste artigo vamos recordar como configurar o DBContext no EF Core em aplicações ASP .NET Core. |
O DbContext
Uma instância da classe DbContext representa uma combinação dos padrões de Unit of Work e Repository de forma que possa ser usada para consultar um banco de dados e agrupar alterações que serão gravadas de volta no armazenamento como uma unidade. (DbContext é conceitualmente semelhante a ObjectContext.)
Uma instância de
DbContext representa uma camada de abstração em
torno dos dados com os quais estamos lidando. Essa abstração existe entre os
dados e os objetos Business/Domain (DDD) de um
aplicativo. Ela permite que você acesse o banco de dados como um objeto (OOP)
de forma simples e fácil, e, não apenas isola os objetos de negócios do código
de acesso ao banco de dados, mas também fornece uma separação clara de
interesses.
Assim, configurar o DbContext no Entity Framework é importante para estabelecer
a conexão e executar as operações CRUD de forma eficiente no armazenamento de dados de
sua escolha.
Configurando o
provedor de banco de dados padrão
Esta deve ser a primeira coisa que faremos ao configurar a instância DbContext,
e, geralmente usamos a classe DbContextOptions que
representa as opções usada pelo DbContext.
Normalmente sobrescrevemos o método OnConfiguring() ou usamos um DbContextOptionsBuilder para criar instâncias dessa classe. Podemos usar DbContextOptions no construtor da classe de contexto para configurar os detalhes do DbContext como provedor do banco de dados, string de conexão, etc.
Para definir as opções do DbContext usamos o método AddDbContext() no método ConfigureServices da classe Startup para injetar o DbContext no contêiner IoC:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllersWithViews();
}
|
No código acima temos :
- O registro da nossa classe de contexto ApplicationDbContext para que fique disponível via injeção de dependência;
- A utilização de DbContextOptionsBuilder que usa o método de extensão UseSQLServer(), que registra o provedor de banco de dados SQL Server a ser usado com o EF Core;
- E a passagem da string de conexão para o método UseSqlServer();
No arquivo de contexto definimos o DbContextOptions<T> que carrega a informação da configuração para o DbContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{ }
public DbSet<Cliente> Clientes { get; set; }
}
|
Tempo de vida do DbContext
O tempo
de vida de um DbContext começa quando a instância é criada e termina quando a
instância é descartada. Uma instância do DbContext foi projetada para ser usada
para uma única Unit of Work. Isso significa que o
tempo de vida de uma instância DbContext é geralmente muito curto.
Podemos usar o
DbContext com o contêiner de injeção de dependência e isso garante que o
DbContext seja criado de acordo com a solicitação do pipeline da API e
descartado com base no gerenciamento de tempo de vida usado durante o registro.
Para isso podemos adicionar o tipo DbContext ao contêiner de serviço usando o
método AddDbContext com tempo de vida do
AddScoped
o que garante que estamos registrando o DbContext como um objeto com escopo
definido. ou seja, cada nova solicitação usará os serviços injetados e,
portanto, o novo DbContext.
Podemos usar o DbContext sem a injeção de dependência, e, assim torna-se responsabilidade do implementador manter o controle de tais recursos e descartá-los manualmente, em vez de compilá-los para você (como vimos acima usando DI).
Outra opção é criar as DbContextOptions externamente e passá-las enquanto cria o contexto, conforme mostrado no exemplo a seguir :
Se não estiver usando DI - então é recomendado usar a instrução "Using" para criar os recursos e descartá-los após seu uso:
using (var context = new EmployeeContext())
{
lsitaClientes = _clienteContext.Clientes.AsEnumerable().Select(x => x.ClienteId).ToList();
}
|
Acessando o DbContext no Repositório ou outros serviços
Finalmente, podemos usar o contexto no controlador ou em outros serviços usando a injeção de dependência, conforme mostrado abaixo :
private readonly
ApplicationDbContext db;
public
HomeController(ApplicationDbContext
EFContext)
{
db
= EFContext;
}
|
Neste cenário é melhor manter a mesma instância vitalícia (AddScoped) para o Repositório/Outros serviços personalizados e DBContext para evitar qualquer problema relacionado à corrupção de dados:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IClienteRepository, ClienteRepository>();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllersWithViews();
}
|
A concorrência com o DbContext
O objeto DBContext
não é seguro para threads, usar AddDbContext(),
entretanto, garante que você está registrando o DBContext como o tempo de vida
AddScoped. ou seja, cada nova solicitação usará a
nova instância de serviço e, portanto, o novo DBContext.
Portanto, idealmente, a simultaneidade é implementada por solicitação básica,
evitando quaisquer problemas de corrupção de dados. No entanto, ele deve ser
protegido de qualquer acesso paralelo dentro do mesmo contexto de solicitação.
É responsabilidade do implementador implementar a simultaneidade ao usá-la em
operações Task/Multithread.
Como boa prática, certifique-se de usar a operação síncrona e assíncrona
corretamente no código :
public async Task<IActionResult> GetIdAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Cliente db = await _clienteContext.Clientes.FindAsync(id);
if (db == null)
{
return NotFound();
}
return Ok(db)
}
|
E estamos conversados...
"Porque Deus
não nos destinou para a ira, mas para a aquisição da salvação, por nosso Senhor
Jesus Cristo,
Que morreu por nós, para que, quer vigiemos, quer durmamos, vivamos juntamente
com ele."
1 Tessalonicenses
5:9,10
Referências:
EF Core - Iniciando com o Entity Framework Core
Core - Usando o EF Core com Windows Forms ..
ASP .NET Core - Acessando dados com Entity ...
EF Core - Conceitos Básicos - Macoratti
EF Core - Usando a abordagem DataBase First
EF Core 2.0 - Scaffolding DbContext e Models .
Curso Entity Framework Core 2.0 - Vídeo Aulas