Saltar al contenido
Abstracción de contexto de Entity Framework

Abstracción de contexto de Entity Framework

En función del tamaño, el ámbito y los requisitos de un proyecto, es posible que haya optado por usar un ORM como Entity Framework sin más abstracción o encapsulación. Las aplicaciones empresariales más grandes pueden necesitar capas y servicios complicados, pero la sobrecarga de desarrollo debe estar justificada.

4min read

En función del tamaño, el ámbito y los requisitos de un proyecto, es posible que haya optado por usar un ORM como Entity Framework sin más abstracción o encapsulación. Las aplicaciones empresariales más grandes pueden necesitar capas y servicios complicados, pero la sobrecarga de desarrollo debe estar justificada.

En lugar de dar una conferencia sobre cuándo usar más abstracciones además del acceso a datos y las abstracciones relacionales de objetos proporcionadas por los ORM, quiero abordar un problema común: que la abstracción se vuelva necesaria en un proyecto existente.

En este artículo se aborda principalmente Entity Framework, pero gran parte de él es aplicable a otros ORM. Mi enfoque es evitar una reescritura y minimizar el impacto del código.

Repositorios en todas partes

Algunas personas ni siquiera admitirán el uso de un contexto EF en un controlador de ASP.NET MVC, un modelo de vista MVVM o un moderador. Menciónalo en un foro o en una conferencia de discusión y es probable que te avergüences por no usar un patrón de plata en particular: Repositorio.

Es un patrón fino, y ya lo estás usando. Sin embargo, no está utilizando la interfaz preferida de esa persona (por ejemplo, IRepository). Algunas versiones causarán una gran cantidad de reescritura. ¡Bienvenido a los sprints 1, 2 y 3 de "refactorización"!

Para evitar este resultado, tenga en cuenta lo que representa el patrón Repository.

"Un repositorio media entre el dominio y las capas de mapeo de datos, actuando como una colección de objetos de dominio en memoria" –P del catálogo EAA

El llamador del repositorio solo conoce algún tipo de colección y no debe preocuparse por el almacenamiento de datos del repositorio. Entity Framework controla la asignación de datos y el repositorio debe tener alguna forma de aceptar criterios de consulta, ya que es probable que la cantidad de datos no sea determinista.

DbSet es un repositorio.

El problema no es la falta de un repositorio; Es el acoplamiento de hormigón. En su lugar, cambie las propiedades DbSet de la clase de contexto a IDbSet. Si tiene algún error en tiempo de compilación, asegúrese de incluir una cláusula using para System.Data.Entity. La clase concrete se deriva de DbQuery, pero la mayoría de sus métodos adicionales también están disponibles como métodos de extensión para IDbSet. Ponerlos en el ámbito de aplicación será suficiente.

Context Interface

En la documentación de MSDN se describe DbContext como un repositorio. Esto es preciso, pero un contexto específico de la aplicación se parece más a una bolsa de repositorio.

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

Las clases derivadas definen propiedades para los distintos tipos de entidad que controla, y los llamadores usan esas propiedades: context. Empleados es más conveniente y legible que el contexto. Set(). Esto es bueno, pero DbContext es mucho más que una bolsa de repositorios. Parte de esta abstracción requiere determinar y definir solo las piezas necesarias.

La interfaz inicial se puede extraer completamente de la clase concreta. Sin embargo, DbContext también representa el patrón de unidad de trabajo, por lo que el contexto también es responsable de guardar y descartar cambios. Al guardar datos, se usa una llamada al método explícito y, si nunca se realiza, los cambios se descartan mediante el patrón desechable.

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

Al reemplazar las declaraciones explícitas de AppContext por IAppContext, se expondrán las dependencias de DbContext. Agregue las piezas faltantes a la interfaz para una compilación limpia y un registro de las dependencias.

¿Qué sigue?

Esta primera parte de la extracción de la interfaz fue divertida, pero también proporciona flexibilidad para las soluciones que utilizan una variedad de patrones de diseño orientados a objetos. Cubriré la tarea más importante en mi próximo artículo: eliminar las dependencias de contexto concretas.

Solicitar una demostración