Pregunta Patrón de Repositorio Estandarización de métodos


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

Mi comprensión original fue esta (extremadamente estúpido)

  • Separe sus Business Objects de sus objetos de datos
  • Estandarice 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 los libros.

Implementació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();
}

Implementación 2:

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

Observe que el primero es Get / Update / GetAll genérico, etc., el segundo es más de lo que yo 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 estandariza las operaciones de acceso en las que veo valor, si implementa esta empresa, las personas fácilmente conocerían 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 parte integral de este patrón? Si ambos son correctos, ¿por qué elegir uno hacer la implementación 2?

Rinoceronte tiene un buen artículo sobre implementación 1, y por supuesto MS tiene un vago definición y un ejemplo de implementación 2 es aquí.


32
2018-04-21 15:29


origen


Respuestas:


En segundo lugar la cita de Fowler citada por oded. Quiero señalar que él dijo "colección-me gusta"Interfaz. La forma en que implemente la interfaz tipo colección depende de usted, pero ni puede ni debe intentar ocultar el hecho de que representa un origen de datos remoto. Por lo tanto, difiere significativamente de una colección en memoria, que no necesita enjuagarse cambios en un almacén de datos remoto. El mecanismo de seguimiento de cambios de su ORM o su solución de rollo propio determina qué tan transparente se puede hacer con la persona que llama. Por lo general, las eliminaciones deben marcarse explícitamente, las inserciones son reconocibles (persistencia por accesibilidad) y las actualizaciones a veces también deben marcarse explícitamente. Combina esto con las complicadas dependencias de tus raíces agregadas y verás que no es muy similar a la colección.

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

Hay una batalla constante entre los defensores de una clase base de repositorio genérico y aquellos que prefieren implementar cada repositorio por sí mismo. 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, algunos de sus agregados solo se pueden eliminar por software (se pueden dividir por omisión de métodos virtuales), mientras que otros pueden no admitir una operación de eliminación.

Asegúrese de comprender las implicaciones de cada enfoque antes de decidir qué ruta tomar. Greg Young tiene una buena publicación sobre los méritos de los repositorios genéricos.

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


14
2018-04-27 12:28



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

Las capas intermedias entre el dominio y las capas de mapeo de datos utilizan una interfaz tipo colección para acceder a objetos de dominio.

Entonces, ambos enfoques son correctos.


7
2018-04-21 15:33



Soy un gran admirador 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 gran limitación, especialmente porque muchas veces el código de 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 a su implementador de IProductRepository acceder al genérico IRepository<Product> a través de la delegación e inyectar eso en el constructor para que pueda componer su clase de posiblemente muchos elementos de IR y agruparlos detrás de una sola interfaz de una manera que tenga sentido.

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


4
2018-04-21 17:23



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 poder acceder a los datos en la tienda subyacente (facilitados fácilmente 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 a procedimiento almacenado para un repositorio basado en SQL), pero la mayoría de las operaciones se pueden completar con la interfaz simple.


2
2018-04-27 12:13



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 genérico de métodos:

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 por Jimmy Bogard, donde también expresa preferencia por la interfaz genérica de repositorio. Suelo seguir eso con una clase base de repositorio genérico que implementa esta interfaz; De esa forma, solo tengo que implementar las cosas que son diferentes para cada entidad de dominio.


1
2018-04-27 13:57



Usualmente 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
2017-11-25 12:26



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


0
2017-07-31 19:25