17

Estoy creando un ORM y trato de averiguar cuáles son las responsabilidades exactas de cada patrón. Digamos que quiero transferir dinero entre dos cuentas, usando la Unidad de trabajo para administrar las actualizaciones en una sola transacción de base de datos. ¿Es correcto el siguiente enfoque?Uso práctico de los patrones de unidad de trabajo y repositorio

  1. obtenerlos del Repositorio
  2. Adjuntar a mi unidad de trabajo
  3. Foro de la transacción comercial & cometió?

Ejemplo:

from = acccountRepository.find(fromAccountId); 
to = accountRepository.find(toAccountId); 

unitOfWork.attach(from); 
unitOfWork.attach(to);  

unitOfWork.begin(); 
from.withdraw(amount); 
to.deposit(amount); 
unitOfWork.commit(); 

Si, como en este ejemplo, la unidad de trabajo y el repositorio de usarse independientemente, o:

  • caso de que la unidad de trabajo utilizar internamente un repositorio y tiene la capacidad de cargar objetos?
  • ... ¿o debería el Depósito usar internamente una Unidad de Trabajo y adjuntar automáticamente cualquier entidad cargada?

¡Todos los comentarios son bienvenidos!

+3

Simplemente curioso, ¿por qué construir ORM cuando hay varios buenos por ahí? –

+1

Solo intento aplicar las mejores prácticas de ORM a PHP. Ya hay algunos, pero no coinciden exactamente con mis expectativas. – Benjamin

+1

+1 Buena pregunta. – Nilesh

Respuesta

16

La respuesta corta sería que el Repositorio estaría utilizando la UoW de alguna manera, pero creo que la relación entre estos patrones es menos concreta de lo que inicialmente parecería. El objetivo de la Unidad de trabajo es crear una forma de agrupar esencialmente un grupo de funciones relacionadas con la base de datos para que puedan ejecutarse como una unidad atómica.A menudo hay una relación entre los límites creados al usar UoW ​​y los límites creados por las transacciones, pero esta relación es más coincidencia.

El patrón Repositorio, por otro lado, es una forma de crear una abstracción que se asemeja a una colección sobre una raíz agregada. La mayoría de las veces, los tipos de cosas que se ven en un repositorio están relacionadas con la consulta o la búsqueda de instancias de la raíz agregada. Una pregunta más interesante (y que no tiene una sola respuesta) es si tiene sentido agregar métodos que se ocupen de algo que no sea la consulta de Agregados. Por un lado, podría haber algunos casos válidos en los que tenga operaciones que se aplicarían a múltiples agregados. Por otro lado, podría argumentarse que si está realizando operaciones en más de un Agregado, en realidad está realizando una sola acción en otro Agregado. Si solo está consultando datos, no sé si realmente necesita crear los límites implícitos en la UoW. Todo se reduce al dominio y cómo se modela.

Los dos patrones se tratan a niveles de abstracción muy diferentes, y la participación de la Unidad de trabajo dependerá de cómo se modelen los Agregados. Los Agregados pueden querer delegar el trabajo relacionado con la persistencia a las Entidades que administran, o podría haber otra capa de abstracción entre los Agregados y el ORM real. Si sus Agregados/Entidades se ocupan de la persistencia ellos mismos, entonces puede ser apropiado que los Repositorios también administren esa persistencia. Si no, entonces no tiene sentido incluir UoW ​​en su repositorio.

Si desea crear algo para el consumo público general fuera de su organización, entonces le sugiero que cree sus interfaces/implementaciones de base Repository de una manera que les permita interactuar directamente con su ORM o no dependiendo de la necesidades del usuario de su ORM. Si esto es interno, y estás haciendo el trabajo de persistencia en tus Aggregates.Entidades, entonces tiene sentido que tu Repositorio haga uso de tu UoW. Para un Repositorio genérico, tendría sentido proporcionar acceso al objeto UoW desde las implementaciones del Repositorio que pueden asegurar que se inicialice y elimine de forma adecuada. En ese sentido, también habrá momentos en los que probablemente desee utilizar varios repositorios dentro de lo que sería un único límite de UoW, por lo que le gustaría poder pasar un UoW ya preparado al depósito en ese caso.

+0

Gracias por esta respuesta completa. Como conclusión, no existe una "mejor" forma de hacerlo, es una cuestión de elección en el contexto global del ORM. – Benjamin

2

¡Buena pregunta!

Depende de cuáles serán los límites de su trabajo. Si van a abarcar varios repositorios, puede que tenga que crear otra abstracción para asegurarse de que se cubran varios repositorios. Sería como una pequeña capa de "servicio" que se define en el Diseño Dirigido por Dominio.

Si su unidad de trabajo va a ser más o menos por Repositorio, me gustaría ir con la segunda opción.

Mi pregunta, sin embargo, para usted sería, ¿cómo puede preocuparse por el repositorio al escribir un ORM? Serán definidos y utilizados por los consumidores de su unidad de trabajo ¿verdad? Si es así, no tiene más opción que simplemente proporcionar una Unidad de trabajo y sus consumidores deberán enlistar los repositorios con su unidad de trabajo y también serán responsables de controlar los límites de la unidad de trabajo. ¿No es así?

+0

Gracias Nilesh. En realidad, mi plan es definir una interfaz limpia para todos estos patrones, junto con una implementación base que pretende ser muy genérica y adaptar la mayoría de las situaciones para nuestro trabajo diario. Ya tengo una implementación funcional de esto, con mapeadores de modelos y datos junto con un registro de mapeador, que proporciona acceso a todos los mapeadores en una sola clase; pero estoy tratando de traspasar los límites para proporcionar soporte para un Repositorio que tenga un Mapa de identidad, con soporte para búsquedas de Criteria y para una Unidad de trabajo, para administrar actualizaciones de la base de datos y para manejar transacciones. – Benjamin

+0

Perdón por ser tan prolijo, necesito más espacio :) ¡Así que me gustaría encontrar una idea genérica de cómo armarlo todo! Su ayuda es muy apreciada. – Benjamin

4

Te recomiendo usar el enfoque cuando el repositorio usa UoW internamente. Este enfoque tiene algunas ventajas, especialmente para la aplicación web.

En la aplicación web, el patrón recomendado para usar UoW ​​es la Unidad de trabajo (sesión) por solicitud HTTP. Entonces, si sus repositorios compartirán UoW, podrá usar el caché de primer nivel (usando el mapa de identidad) para el objeto que fueron solicitados por otros repositorios (como diccionarios de datos a los que hacen referencia múltiples agregados). Además, deberá comprometer solo una transacción en lugar de múltiple, por lo que funcionará mucho mejor en términos de rendimiento.

Puede echar un vistazo a los códigos fuente de Hibernate/NHibernate que son ORM maduros en Java/.NET world.

+0

¡Gracias por compartir tu punto de vista! – Benjamin

Cuestiones relacionadas