Ir para o conteúdo
Abstração de contexto do Entity Framework

Abstração de contexto do Entity Framework

Dependendo do tamanho, do escopo e dos requisitos de um projeto, você pode ter optado por usar um ORM como o Entity Framework sem abstração ou encapsulamento adicional. Aplicativos corporativos maiores podem precisar de camadas e serviços complicados, mas a sobrecarga de desenvolvimento deve ser justificada.

4min read

Dependendo do tamanho, do escopo e dos requisitos de um projeto, você pode ter optado por usar um ORM como o Entity Framework sem abstração ou encapsulamento adicional. Aplicativos corporativos maiores podem precisar de camadas e serviços complicados, mas a sobrecarga de desenvolvimento deve ser justificada.

Em vez de dar palestras sobre quando usar mais abstrações sobre o acesso a dados e abstrações objeto-relacionais fornecidas pelos ORMs, quero abordar um problema comum: a abstração se tornando necessária em um projeto existente.

Este artigo aborda principalmente o Entity Framework, mas grande parte dele é aplicável a outros ORMs. Minha abordagem é evitar uma reescrita e minimizar o impacto do código.

Repositórios em todos os lugares

Algumas pessoas nem admitem usar um contexto EF em um controlador ASP.NET MVC, um modelo de exibição MVVM ou um apresentador. Mencione-o em um fórum ou discussão em conferência e você provavelmente ficará envergonhado por não usar um padrão específico de bala de prata: Repositório.

É um padrão fino e você já o está usando. No entanto, você não está usando a interface preferida dessa pessoa (por exemplo, IRepository). Algumas versões causarão grandes quantidades de reescrita. Bem-vindo à "refatoração" dos sprints 1, 2 e 3!

Evite esse resultado considerando o que o padrão Repository representa.

"Um repositório faz a mediação entre as camadas de domínio e mapeamento de dados, agindo como uma coleção de objetos de domínio na memória" –P do Catálogo EAA

O chamador do repositório só está ciente de algum tipo de coleção e não deve se preocupar com o armazenamento de dados do repositório. O Entity Framework lida com o mapeamento de dados e o repositório deve ter alguma maneira de aceitar critérios de consulta, pois a quantidade de dados provavelmente não é determinística.

DbSet é um repositório.

O problema não é a falta de um repositório; é o acoplamento de concreto. Em vez disso, altere as propriedades DbSet da classe de contexto para IDbSet. Se você tiver erros em tempo de compilação, inclua uma cláusula using para System.Data.Entity. A classe concreta deriva de DbQuery, mas a maioria de seus métodos extras também está disponível como métodos de extensão para IDbSet. Trazê-los para o escopo resolverá o problema.

Context Interface

A documentação do MSDN descreve o DbContext como um repositório. Isso é preciso, mas um contexto específico do aplicativo é mais como um repositório de repositórios.

public class AppContext : DbContext
{
    public IDbSet<Department> Departments { get; set; }
    public IDbSet<Employee> Employees { get; set; }
    public IDbSet<Person> People { get; set; }
}

As classes derivadas definem propriedades para os vários tipos de entidade que manipulam e os chamadores usam essas propriedades: context. Funcionários é mais conveniente e legível do que o contexto. Conjunto(). Isso é bom, mas DbContext é muito mais do que um repositório de repositórios. Parte dessa abstração requer determinar e definir apenas as peças necessárias.

A interface inicial pode ser extraída completamente da classe concreta. No entanto, DbContext também representa o padrão Unidade de Trabalho, portanto, o contexto também é responsável por salvar e descartar alterações. O salvamento de dados usa uma chamada de método explícita e, se nunca for feito, as alterações serão descartadas usando o padrão descartável.

 public interface IAppContext : IDisposable
 {
      IDbSet<Department> Departments { get; set; }
      IDbSet<Employee> Employees { get; set; }
      IDbSet<Person> People { get; set; }
      int SaveChanges();
      Task<int> SaveChangesAsync();
 }
  
public class AppContext : DbContext, IAppContext
{
     public IDbSet<Department> Departments { get; set; }
     public IDbSet<Employee> Employees { get; set; }
     public IDbSet<Person> People { get; set; }
}

Substituir declarações explícitas de AppContext por IAppContext exporá dependências de DbContext. Adicione as peças que faltam à interface para uma compilação limpa e um registro das dependências.

Qual é o próximo

Essa primeira extração de interface foi divertida, mas também oferece flexibilidade para soluções que usam uma variedade de padrões de design orientados a objetos. Abordarei a tarefa mais importante em meu próximo artigo: remover as dependências de contexto concretas.

Solicite uma demonstração