Patrón de repositorio vs DAL


93

¿Son la misma cosa? Acabo de terminar de ver el tutorial de Storefront de Rob Connery y parecen ser técnicas similares. Quiero decir, cuando implemento un objeto DAL, tengo los métodos GetStuff, Add / Delete, etc. y siempre escribo la interfaz primero para poder cambiar db más tarde.

¿Estoy confundiendo las cosas?

Respuestas:


88

Definitivamente no eres tú quien confunde las cosas. :-)

Creo que la respuesta a la pregunta depende de qué tan purista quieras ser.

Si desea un punto de vista estricto de DDD, eso lo llevará por un camino. Si miras el repositorio como un patrón que nos ha ayudado a estandarizar la interfaz de la capa que separa los servicios y la base de datos, te bajará otra.

Desde mi perspectiva, el repositorio es solo una capa de acceso a los datos claramente especificada, o en otras palabras, una forma estandarizada de implementar su capa de acceso a los datos. Existen algunas diferencias entre las diferentes implementaciones de repositorios, pero el concepto es el mismo.

Algunas personas pondrán más restricciones DDD en el repositorio, mientras que otras usarán el repositorio como un mediador conveniente entre la base de datos y la capa de servicio. Un repositorio como un DAL aísla la capa de servicio de las especificaciones de acceso a datos.

Un problema de implementación que parece hacerlos diferentes, es que un repositorio se crea a menudo con métodos que toman una especificación. El repositorio devolverá datos que satisfagan esa especificación. La mayoría de los DAL tradicionales que he visto tendrán un conjunto más grande de métodos donde el método tomará cualquier número de parámetros. Si bien esto puede parecer una pequeña diferencia, es un gran problema cuando ingresa a los reinos de Linq y Expressions. Nuestra interfaz de repositorio predeterminada se ve así:

public interface IRepository : IDisposable
{
    T[] GetAll<T>();
    T[] GetAll<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
    void Delete<T>(T entity);
    void Add<T>(T entity);
    int SaveChanges();
    DbTransaction BeginTransaction();
}

¿Es esto un DAL o un repositorio? En este caso, supongo que son ambos.

Kim


5
Llega tarde a la fiesta aquí, pero ¿por qué T [], no List <T> (o similar)?
Mike Kingscott

27
Quizás IEnumerable <T> sería el mejor.
Venemo

9
o IQueryable <T>
kenwarner

1
Creo que IQueryable <T> sería la mejor opción, porque le permite encadenar métodos y diferir la ejecución, dejando que la base de datos haga todo el trabajo.
0lukasz0

4
@kenwarner Creo que devolver IQueryable <T> filtra la abstracción. Debe devolver los objetos de dominio de su repositorio.
Mateo

42

Un repositorio es un patrón que se puede aplicar de muchas formas diferentes, mientras que la capa de acceso a datos tiene una responsabilidad muy clara: el DAL debe saber cómo conectarse a su almacenamiento de datos para realizar operaciones CRUD.

Un repositorio puede ser un DAL, pero también puede ubicarse frente al DAL y actuar como un puente entre la capa de objetos de negocio y la capa de datos. La implementación que se utilice variará de un proyecto a otro.


23

Una gran diferencia es que un DAO es una forma genérica de lidiar con la persistencia de cualquier entidad en su dominio. Un repositorio, por otro lado, solo se ocupa de las raíces agregadas.


26
Lo primero que hay que entender es que un repositorio como patrón es parte de un sistema más grande conocido como Diseño controlado por dominio. En el dominio DDD, los objetos se agrupan en agregados, cada uno con una raíz agregada. Por ejemplo, PurchaseOrder es una raíz agregada y OrderItems son elementos secundarios dentro de la raíz agregada. Un repositorio solo se ocupa de raíces agregadas. Es decir, un artículo de pedido, por ejemplo, nunca se carga independientemente de su raíz agregada. Por lo tanto, nunca tendría un repositorio de OrderItem en DDD. Sin embargo, en un sistema que no sea DDD, podría tener un OrderItemDao ya que Dao no está restringido a raíces agregadas.
pondermático

NG, ¡Gracias! Había comenzado a verlo de esa manera, pero esto lo deja claro. ¡Tendré que empezar a leer toda la literatura de DDD!
David

@bingle, gran descripción de las raíces agregadas y cómo un repositorio carga los objetos secundarios. ¿Dónde existiría un repositorio en una aplicación de varias capas? Pude ver que está en una biblioteca de capas de acceso a datos, pero como carga objetos secundarios, ¿debería existir en la biblioteca de capas lógicas? Mi instinto me dice la capa de acceso a datos, pero quería tu opinión al respecto.
Jeff LaFay

12

Estaba buscando una respuesta a una pregunta similar y estoy de acuerdo con las dos respuestas mejor clasificadas. Tratando de aclarar esto por mí mismo, descubrí que si las Especificaciones, que van de la mano con el patrón de Repositorio, se implementan como miembros de primera clase del modelo de dominio, entonces puedo

  • reutilizar definiciones de especificación con diferentes parámetros,
  • manipular los parámetros de las instancias de especificación existentes (por ejemplo, para especializarse),
  • combinarlos ,
  • realizar la lógica empresarial en ellos sin tener que acceder a la base de datos,
  • y, por supuesto, pruébelos unitarios independientemente de las implementaciones reales del Repositorio.

Incluso puedo ir tan lejos y afirmar que a menos que el patrón Repository se use junto con el patrón Specification, no es realmente "Repository", sino un DAL. Un ejemplo artificial en pseudocódigo:

specification100 = new AccountHasMoreOrdersThan(100)
specification200 = new AccountHasMoreOrdersThan(200)

assert that specification200.isSpecialCaseOf(specification100)

specificationAge = new AccountIsOlderThan('2000-01-01')

combinedSpec = new CompositeSpecification(
    SpecificationOperator.And, specification200, specificationAge)

for each account in Repository<Account>.GetAllSatisfying(combinedSpec)
    assert that account.Created < '2000-01-01'
    assert that account.Orders.Count > 200

Consulte el Ensayo de especificación de Fowler para obtener más detalles (en eso me basé lo anterior).

Un DAL tendría métodos especializados como

IoCManager.InstanceFor<IAccountDAO>()
    .GetAccountsWithAtLeastOrdersAndCreatedBefore(200, '2000-01-01')

Puede ver cómo esto puede volverse engorroso rápidamente, especialmente porque tiene que definir cada una de las interfaces DAL / DAO con este enfoque e implementar el método de consulta DAL.

En .NET, las consultas LINQ pueden ser una forma de implementar especificaciones, pero la combinación de Especificación (expresiones) puede no ser tan sencilla como con una solución propia. Algunas ideas para eso se describen en esta Pregunta SO .


2

Mi opinión personal es que se trata de mapeo, consulte: http://www.martinfowler.com/eaaCatalog/repository.html . Entonces, la salida / entrada del repositorio son objetos de dominio, que en el DAL podrían ser cualquier cosa. Para mí, esa es una adición / restricción importante, ya que puede agregar una implementación de repositorio para una base de datos / servicio / lo que sea con un diseño diferente, y tiene un lugar claro para concentrarse en hacer el mapeo. Si no usara esa restricción y tuviera el mapeo en otro lugar, entonces tener diferentes formas de representar los datos puede afectar el código en lugares donde no debería cambiar.


1

Se trata de interpretación y contexto. Pueden ser muy similares o de hecho muy diferentes, pero mientras la solución funcione, ¡qué hay en un nombre!


1

El repositorio es un patrón, esta es una forma de implementar las cosas de manera estandarizada para reutilizar el código como podamos.


1

La ventaja de usar el patrón de repositorio es simular su capa de acceso a datos, de modo que pueda probar su código de capa empresarial sin llamar al código DAL. Hay otras grandes ventajas, pero esto me parece muy importante.


1
Aún puede simular un DAL, no es necesario que sea un repositorio per se. El punto importante es que cualquiera que sea la estrategia de acceso a datos que utilice, debe implementar una interfaz. Esto le permitirá usar contenedores de IoC, así como probar cuidadosamente su código comercial sin necesidad de un almacén de datos.
cdaq

0

Por lo que entiendo, pueden significar básicamente lo mismo, pero el nombre varía según el contexto.

Por ejemplo, puede tener una clase Dal / Dao que implemente una interfaz IRepository.

Dal / Dao es un término de capa de datos; los niveles más altos de su aplicación piensan en términos de repositorios.


0

Entonces, en la mayoría de los casos (simples), ¿DAO es una implementación de Repository?

Por lo que tengo entendido, parece que DAO se ocupa precisamente del acceso a la base de datos (CRUD - ¡¿Sin embargo, sin selecciones?!), Mientras que Repository le permite abstraer todo el acceso a los datos, quizás siendo una fachada para múltiples DAO (tal vez diferentes fuentes de datos).

¿Estoy en el camino correcto?


En realidad, lo revertiría y diría que, desde un punto de vista simplista, un repositorio es un estilo de implementación particular para un DAO, pero sí, estás en el camino correcto. (R de CRUD = Leer, así que esa es su selección.)
Jeromy Irvine

0

En el mundo externo (es decir, el código de cliente), el repositorio es el mismo que DAL, excepto:

(1) sus métodos de inserción / actualización / eliminación están restringidos para tener el objeto contenedor de datos como parámetro.

(2) para la operación de lectura, puede requerir una especificación simple como un DAL (por ejemplo, GetByPK) o una especificación avanzada.

Internamente, trabaja con una capa de mapeador de datos (por ejemplo, el contexto del marco de la entidad, etc.) para realizar la operación CRUD real.

Qué no significa el patrón de repositorio: -

Además, he visto que la gente a menudo se confunde al tener un método Save separado como la implementación de muestra del patrón de repositorio además de los métodos Insert / Update / Delete que confirma todos los cambios en la memoria realizados por los métodos de inserción / actualización / eliminación en la base de datos. Podemos tener un método Save definitivamente en un repositorio, pero esa no es la responsabilidad del repositorio para aislar CUD (Crear, Actualizar, Eliminar) en memoria y los métodos de persistencia (que realiza la operación de escritura / cambio real en la base de datos), pero el responsabilidad del patrón de Unidad de Trabajo.

¡Espero que esto ayude!


0

Se podría argumentar que un "repositorio" es una clase específica y un "DAL" es la capa completa que consta de los repositorios, DTO, clases de utilidad y cualquier otra cosa que se requiera.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.