Tipos de repositorio: El repositorio concreto

En el post anterior hablaba sobre el repositorio genérico y, para variar, me quejaba de algunas cosas. Las que menos me gustan del repositorio genérico son:

  • Contamina el dominio: se exponen al dominio los mismos métodos para todas las entidades, permitiendo realizar operaciones que quizá no fuesen deseables.
  • Los métodos FindXXX que devuelven varias entidades muchas veces generan problemas de eficiencia en el acceso a datos.

Para solventar el primer punto, hay una solución muy sencilla:

El repositorio concreto

No sabía muy bien como llamarlo, pero por contraposición al genérico, concreto me ha parecido un buen nombre. Un repositorio concreto se define para una sóla entidad y únicamente con los métodos necesarios para esa entidad. Un ejemplo típico:

public interface ICustomerRepository
{
   Customer FindById(Guid id);
   void Add(Customer customer);
   IEnumerable<Customer> FindPreferred();
   IEnumerable<Customer> FindWithOrdersInTheLastMonth();
}

La ventaja de esta implementación es que nos permite controlar exactamente qué se puede hacer con cada entidad y gana en expresividad porque se puede utilizar el lenguaje ubicuo para nombrar los métodos del repositorio.

Un inconveniente es que obliga a definir un interface diferente para el repositorio de cada entidad. En mi opinión esto no debería ser un problema porque realmente cada entidad va a tener operaciones diferentes y no debería ser necesario duplicar mucho más que el método FindById.

Un factor muy importante a tener en cuenta al implementar este tipo de repositorios es que el hecho de utilizar interfaces concretos no quiere decir que no podamos aprovechar una implementación genérica. Al usar este tipo de repositorios, en la implementación se puede encapsular un repositorio genérico con lo que se consigue reutilizar gran parte del código:

public class CustomerRepository : ICustomerRepository
{
   private readonly Repository<Customer> repository;

   // Constructor para inyectar repository

   public void Add(Customer customer)
   {
       repository.Add(customer);
   }    

   public IEnumerable<Customer> FindPreferred()
   {
        return repository.Find(Query.For<Customer>(customer => customer.IsPreferred));.
   }
   // Resto de métodos . . .
}

Aunque esta implementación me gusta bastante más que el repositorio genérico, sigue teniendo sus problemas. Una parte que no me acaba de gustar es que muchas veces el repositorio concreto lo único que hace es redirigir llamadas a los métodos del repositorio genérico que encapsula.

Además, seguimos sin resolver el problema de los FindXXX, especialmente en lo referente a leer información para la capa de presentación, porque seguimos cargando siempre entidades completas, sin tener en cuenta si queremos precargar o no sus relaciones y eso puede dar muchos problemas de eficiencia que luego son complicados de resolver con esta arquitectura.

En el siguiente post empezaremos con la parte interesante de toda esta historia sobre repositorios viendo otra alternativa a la implementación de los repositorio: El no-repositorio.

2 comentarios en “Tipos de repositorio: El repositorio concreto

  1. Con repecto alo comentas de la especificación de la carga adicional y demás podrías usar roles explícitos o algún mecanismo de especificación para tus prefetch…

    Unai

  2. Sí, esa es una salida. Supongo que te refieres a cosas como estas:

    http://www.udidahan.com/2007/09/16/fetching-strategy-nhibernate-implementation-available/

    http://www.udidahan.com/2007/04/23/fetching-strategy-design/

    A mi la idea de tener que hacer explícito desde el usuario del repositorio el tipo de fetch no me gusta mucho porque me parece que acopla el cliente a la estrategia de persistencia (sobre todo al mapeo de tablas).

    La idea de los roles debo reconocer que siempre me ha parecido atractiva, pero nunca he llegado a implementarla. ¿Conoces algun ejemplo bueno para echarle un vistazo?

Comentarios cerrados.