Estandarización del patrón de métodos del repositorio


Todo lo que estoy tratando de encontrar la definición correcta del patrón de repositorio.

Mi entendimiento original era este (extremadamente aturdido)

  • Separe sus Objetos de Negocio de sus Objetos de Datos
  • Estandarizar los métodos de acceso en la capa de acceso a datos.

Realmente he visto 2 implementaciones diferentes, y no hay ejemplos formales en línea, los que he visto están escondidos en libros.

Aplicación 1 :

public Interface IRepository<T>{
      List<T> GetAll();
      void Create(T p);
      void Update(T p);
}


public interface IProductRepository: IRepository<Product> {
      //Extension methods if needed
       List<Product> GetProductsByCustomerID();
}

Aplicación 2 :

public interface IProductRepository {
      List<Product> GetAllProducts();
      void CreateProduct(Product p);
      void UpdateProduct(Product p);
      List<Product> GetProductsByCustomerID();
}

Observe que el primero es genérico Get/Update/getAll, etc., el segundo es más de lo que definiría como "DAO".

Ambos comparten una extracción de sus entidades de datos. Lo cual me gusta, pero puedo hacer lo mismo con un simple DAO. Sin embargo, la segunda pieza estandarizar las operaciones de acceso que veo valor en, si se implementa esta empresa amplia gente sabría fácilmente el conjunto de métodos de acceso para su repositorio.

¿Me equivoco al asumir que la estandarización del acceso a los datos es una pieza integral de este patrón ? Si ambos son correctos, ¿por qué uno elegiría hacer la implementación 2?

Rhino tiene un buen artículo sobre la implementación 1, y por supuesto MS tiene una definición vaga y un ejemplo de implementación 2 es aquí.

Author: Nix, 2010-04-21

7 answers

Secundo la cita de Fowler citada por oded. Quiero señalar que dijo" colección-como " interfaz. Cómo implementar la colección como interfaz es sin duda depende de usted, pero ni puede ni debe tratar de ocultar el hecho de que representa una fuente de datos remota. Por lo tanto, difiere significativamente de una colección en memoria, que no necesita vaciar los cambios en un almacén de datos remoto. El mecanismo de seguimiento de cambios de su solution o su solución roll-your-own determina cómo transparente esto se puede hacer a la persona que llama. Las eliminaciones generalmente deben marcarse explícitamente, las inserciones son detectables (persistencia por accesibilidad) y las actualizaciones a veces también deben marcarse explícitamente. Combine esto con las dependencias complicadas de sus raíces agregadas y verá que no es muy colección como.

No existe tal cosa como "la implementación cannonical del repositorio".

Hay una batalla constante entre los defensores de un repositorio genérico clase base y aquellos que prefieren implementar cada repositorio por su cuenta. Si bien la implementación genérica es atractiva en escenarios simples, muy a menudo encontrará que es una abstracción muy permeable. Por ejemplo, es posible que algunos de sus agregados solo se eliminen por software (cistomizables mediante anulaciones de métodos virtuales), mientras que otros pueden no admitir una operación de eliminación en absoluto.

Asegúrese de comprender las implicaciones de cada enfoque antes de decidir qué ruta tomar. Greg Young tiene un buen post en los méritos de los repositorios genéricos.

Http://codebetter.com/blogs/gregyoung/archive/2009/01/16/ddd-the-generic-repository.aspx

 15
Author: Johannes Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-27 12:38:23

De Martin Fowler "Patrones de Arquitectura de Aplicaciones Empresariales", la definición del Patrón de repositorio es:

Media entre el dominio y las capas de asignación de datos mediante una interfaz similar a una colección para acceder a los objetos de dominio.

Por lo tanto, ambos enfoques son correctos.

 7
Author: Oded,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-21 15:33:04

Soy un gran fan del patrón de repositorio genérico, pero creo que debería considerar no heredar directamente de la interfaz, ya que puede convertirse en una limitación muy grande, especialmente porque muchas veces el código para la interfaz genérica será el mismo que podría definirse en una clase base abstracta que ya no podrá tener más de 1 repositorio genérico dentro de una clase.

Recomiendo que su implementador IProductRepository acceda al genérico IRepository<Product> a través de la delegación e inyecte eso a través del constructor para que pueda componer su clase de posiblemente muchos IRepositorios y agruparlos detrás de una sola interfaz de una manera que tenga sentido.

Escribí un blog sobre este tema mientras hace referencia específicamente a NHibernate este patrón se puede aplicar a cualquier tipo de repositorio: Creando un Repositorio NHiberate genérico y extensible común versión 2

 4
Author: Chris Marisic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-21 17:23:54

Con la introducción de LINQ en. NET, un patrón de repositorio genérico se vuelve mucho más fácil de realizar:

public interface IRepository<T> : IQueryable<T>
{
    void Add(T item);
    void Remove(T item);
}

Para calificar como un repositorio, simplemente necesita ser capaz de acceder a los datos en el almacén subyacente (fácilmente proporcionado por IQueryable) y modificar los datos contenidos.

Puede proporcionar extensiones a la interfaz base para proporcionar ganchos para un comportamiento más específico de la entidad (como el cableado en una llamada de procedimiento almacenado para un repositorio basado en SQL), pero la mayoría de las operaciones pueden ser completado por la interfaz simple.

 2
Author: Paul Turner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-27 12:13:53

Además de su interfaz de repositorio genérico (implementación 1) y su variación en el repositorio específico de roles (implementación 2), también puede considerar un repositorio de método genérico:

public interface IRepository
{
    void Save<ENTITY>(ENTITY entity) where ENTITY : DomainEntity;

    ENTITY Load<ENTITY>(Guid id) where ENTITY : DomainEntity;

    IQueryable<ENTITY> Query<ENTITY>() where ENTITY : DomainEntity;

    IQueryable<ENTITY> Query<ENTITY>(IDomainQuery<ENTITY> whereQuery)
        where ENTITY : DomainEntity;
}

Esta tercera versión proviene de este blogpost de Jimmy Bogard, donde también expresa su preferencia por la interfaz genérica del repositorio. Suelo seguir eso con una clase base de repositorio genérica que implementa esta interfaz; de esa manera, solo tengo que implementar las cosas que es diferente para cada entidad de dominio.

 1
Author: tijmenvdk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-27 13:57:06

Normalmente uso el repositorio genérico con composición en lugar de herencia. Eso me da la ventaja de una implementación genérica, con el control de qué métodos exponer.

Algo como esto:

public Interface IRepository<T>{
  List<T> GetAll();
  void Create(T p);
  void Update(T p);
}


public interface IProductRepository {
  //Extension methods if needed
   List<Product> GetProductsByCustomerID();
   List<T> GetAll();
   void Create(T p);
   //Let assume here you should not be able to update the products
}

public ProductRepository : IProductRepository {
    private IRepository _repository;

    public ProductRepository(IRepository repository) {
        this._repository = repository;
    }

       List<T> GetAll() 
       {
            _repository.GetAll();
       }

       void Create(T p) 
       {
            _repository.Create(p);
       }

       List<Product> GetProductsByCustomerID() 
       {
          //..implementation goes here
       }
}
 0
Author: user0b101010,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-25 12:26:49

El patrón de repositorio es uno de los patrones más utilizados en el desarrollo de software. Hay muchos post que se pueden marcar como respuesta a su pregunta. Algo que me gusta destacar es el hecho de que una buena implementación de repositorio se mejorará si se utiliza IoC (Autofac, Windsor, etc...). He estado jugando hace mucho tiempo con algunos ADO.NET frameworks basados (LinqToSql, EF) y NHibernate. Siempre puede obtener beneficios de una implementación genérica si utiliza IoC. Puede definir interfaces para sus repositorios específicos y resolver cuando realmente necesita algunas acciones específicas.

 0
Author: Miguel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-31 19:25:21