19

Después de leer un montón de artículos, todavía no estoy seguro de las responsabilidades del patrón de unidad de trabajo al interactuar con repositorios.Interacción entre unidad de trabajo y patrones de repositorio

repositorios son responsables de cargar y guardar entidades raíz de agregados, así que considere el siguiente código de ejemplo:

using(IUnitOfWork uow = container.CreateUnitOfWork()) 
{ 
    Repository<ARoot> roots = container.GetRepository<ARoot>(); 
    ARoot root = root.FindByName("ARoot"); 
    root.Name = "ANewName"; 

    roots.Save(root); 
    uow.Commit(); 
} 

La unidad de interfaz de trabajo se define con los siguientes métodos:

public interface IUnitOfWork 
{ 
    void Insert(object); 
    void Update(object);   
    void Delete(object); 
    void Commit(); 
    void Rollback(); 
} 

Lets decir que el repositorio se implementa utilizando un SQL Mapper muy sencillo, por lo que FindByName contiene algunos SQL directos para devolver ARoot, la implementación de Save se vería así:

public void Save(T entity) 
{ 
     IUnitOfWork uow = GetUnitOfWork(); 
     // Tell the UOW we are updating this entity 
     uow.Update(entity); 
} 

El código de Compromiso de la Unidad de Trabajo construiría entonces todos los SQL necesarios para volver a asignar la entidad al DB?

Pregunta 2)

Si añado una raíz agregada a la unidad de trabajo, es la unidad de trabajo responsable de persisiting la raíz, y sus enitities niño, o debería ser el método Save del repositorio añadir el las entidades modificadas en la Unidad de trabajo? por ejemplo

public void Save(T entity) 
{ 
     IUnitOfWork uow = GetUnitOfWork(); 
     // Tell the UOW we are updating this entity 
     uow.Update(entity); 
     uow.Update(entity.AChildObject); 
} 

O ... Alternativly

¿Una unidad de trabajo sólo se ocupan con raíces agregados, y cuando llama cometido el repositorio Guardar métodos para cada objeto en su conjunto de cambios, manteniendo el código SQL para la cartografía persistir la entidad en el repositorio, cambiando el primer ejemplo de código para

using(IUnitOfWork uow = container.CreateUnitOfWork()) 
{ 
    Repository<ARoot> roots = container.GetRepository<ARoot>(); 
    ARoot root = root.FindByName("ARoot"); 
    root.Name = "ANewName"; 

    //roots.Save(root); 
    uow.Update(root); 
    // and commit 
    uow.Commit(); 
} 

Gracias,

James

Respuesta

3

En nuestro proyecto utilizamos un Repositorio para comportarnos como una colección de Entidades, y UnitOfWork se usa para rastrear los cambios en esas entidades, y para volver a escribirlas en el almacén de datos.

Si está utilizando LinqToSql u otro O OR Mapper, entonces es probable que implemente un patrón de UnitOfWork en sí mismo, tan a menudo que solo la instancia de ORMapper en nuestro propio IUnitOfWork.

Nuestra interfaz de repositorio es generalmente algo como ..

IEnumerable<Order> FindByCustomerId(string customerId); 
    void Add(Order order); 
    void Remove(Order order); 

No tenemos ningún método para guardar en el repositorio. Si no necesitamos un UnitOfWork, entonces los métodos Agregar/Quitar actúan directamente en el almacén de datos.

Si necesitamos un UnitOfWork, a continuación, la interfaz pública es algo así como ...

void Commit(); 
void Rollback(); 

El repositorio tiene una interfaz interna con el UnitOfWork, por lo que cuando consultamos el repositorio, los objetos devueltos son seguidos por la UnitOfWork para cambios. El método de confirmación escribe los cambios en el almacén de datos, el método de deshacer simplemente borra sus cambios.

Cuando usamos LinqToSql el DataContext se encarga del seguimiento de cambios, en Rollback simplemente instanciamos un nuevo contexto. La persistencia se maneja a través de la raíz y sus hijos. Una instancia de UnitOfWork se comparte entre todos los repositorios.

Cuando no usamos LinqToSql, implementamos nuestro propio UnitOfWork, tal vez llama a un servicio web o algo así, en este caso sí modificamos el seguimiento en las clases de entidad utilizando una clase EntityBase.

Tenemos un repositorio para cada raíz, pero a veces los hijos de una raíz se usan como raíces, por lo que a menudo necesitamos algo como un OrderLineRepository, porque tenemos un caso de uso en nuestro sistema si el usuario quiere buscar Líneas de pedido.

3

Normalmente, la forma en que me gusta verlo es que UoW realiza un seguimiento de los cambios que se guardan llamando directamente a IRepository.Save().

También prefiero que el código UoW se maneje como un aspecto y fuera de las interacciones con el dominio. Esto significa que es manejado por algunos controladores de comandos globales o el código de servicios web como parte de completar la solicitud. En otras palabras, al iniciar una solicitud se abre una unidad de trabajo, y la finaliza. De esta forma, el dominio puede ignorar la UoW y su implementación.

La comisión de la unidad de trabajo es lo que hace que los cambios realizados al llamar a .Save() y otros métodos de cambio persistan. Muy posiblemente, la UoW es lo que está rastreando estos cambios de alguna manera.

2
  • UnitOfWork es su transacción manejador
  • repositorio está haciendo el trabajo acutal para cargar/guardar objetos a el almacén de datos

que usan definiciones similares a:

IUnitOfWork { Commit(); } 
IRepository { GetAll(); GetById(); Add(T item); Remove(T item); } 

No quisiera que UnitOfWork creara SQL, esa lógica estaría en su Repositorio. ¿Qué tienda de datos estás usando?

Cuestiones relacionadas