2011-04-07 7 views
7

Después de haber creado una pequeña aplicación utilizando el patrón de unidad de trabajo/repositorio, me cuesta entender cómo usar esto correctamente en mi capa de negocios. Mi aplicación tiene una capa de acceso a datos que puede ser NHibernate o Entity Framework. Puedo cambiar entre estos fácilmente.¿Cuál es la forma correcta de usar la Unidad de trabajo/Repositorios dentro de la capa empresarial?

Tengo varios repositorios, por ejemplo, Cliente, Orden, etc. Mi unidad de trabajo será una ISesión o un Contexto de Objeto dependiendo de con qué DAL quiero probar.

Mi capa empresarial contiene un único método de negocio - CreateOrder(). Lo que estoy luchando por comprender es en qué parte de la capa empresarial debería estar inicializando mi unidad de trabajo y mis repositorios.

Centrándose en Nhibernate, mi DAL parece:

public class NHibernateDAL : IUnitOfWork 
{ 
    log4net.ILog log = log4net.LogManager.GetLogger(typeof(NHibernateDAL)); 
    ISession context; 

    public NHibernateDAL() 
    {    
     context = SessionProvider.OpenSession(); 
     this.Context.BeginTransaction(); 
     CurrentSessionContext.Bind(context);    
    } 

    public ISession Context 
    { 
     get { return context; } 
    } 

    public void Commit() 
    {   
     this.Context.Transaction.Commit(); 
     context.Close();    
    } 

    public void Dispose() 
    { 
     ISession session = CurrentSessionContext.Unbind(SessionProvider.SessionFactory); 
     session.Close(); 
    } 
} 

Dentro de mi capa de negocio, quiero saber dónde debería estar declarando mi unidad de trabajo y repositorios. ¿Están declarados a nivel de clase o dentro del método CreateOrder?

Por ejemplo:

public class BusinessLogic 
{   
    UnitOfWork _unitOfWork = new UnitOfWork(NHibernateDAL); 
    NhRepository<Order> _orderRepository = new NhRepository<Order>(_unitOfWork);  
    NhRepository<Customer> _customerRepository = new NhRepository<Customer>(_unitOfWork); 
    .... 

    public void CreateOrder(.....) 
    { 
     Order order = new Order(); 
     _orderRepository.Add(order); 

     _unitOfWork.Commit(); 
    } 
} 

El código anterior sólo funciona por primera vez el método createOrder() se llama, pero no para las llamadas posteriores debido a que la sesión se cierra. He intentado eliminar la llamada 'context.Close()' después de confirmar la transacción, pero esto también falla. Aunque el enfoque anterior no funciona, me parece más correcto declarar mis repositorios y unidad de trabajo con este alcance.

Sin embargo, si lo implemento de la siguiente manera, en cambio funciona bien, pero parece antinatural declarar los repositorios y la unidad de trabajo dentro del alcance del método en sí. Si tuviera una tonelada de métodos de negocio entonces estaría declarando repositorios y unidades de trabajo por todo el lugar:

public class BusinessLogic 
{      
    public void CreateOrder(.....) 
    { 
     UnitOfWork _unitOfWork = new UnitOfWork(NHibernateDAL); 
     var _orderRepository = new NhRepository<Order>(_unitOfWork);  

     NhRepository<Customer> _customerRepository = null; 
     Order order = new Order(); 
     _orderRepository.Add(order);    

     _unitOfWork.Commit(); 
    } 
} 

Si tuviera que aplicar esto con declaración de nivel de clase, entonces creo que necesitaría algún medio de re -Abrir la misma unidad de trabajo al comienzo del método CreateOrder.

¿Cuál es la forma correcta de usar la unidad de trabajo y los repositorios dentro de la capa empresarial?

Respuesta

1

Me parece que casi lo tienes. En nuestra nueva pila de servidores tengo esta configuración:

WCF Service Layer --> just returns results from my Business Layer 

My business layer is called, creates a unitofwork, creates the respository 
Calls the respository function 
Uses AutoMapper to move returned results into a DTO 

My repository gets the query results and populates a composite object. 

Parece casi lo que tienes allí. Aunque usamos Unity para ubicar lo que usted llama la capa de negocios. (simplemente lo llamamos nuestro procesador de funciones)

Lo que sugeriría, sin embargo, es que NO mantenga el UnitOfWork en el nivel de clase. Después de todo, cada función descreet es una unidad de trabajo. Así que la mía es como esto (los nombres han sido cambiados para proteger a los inocentes):

 using (UnitOfWorkScope scope = new UnitOfWorkScope(TransactionMode.Default)) 
     { 
      ProcessRepository repository = new ProcessRepository(); 
      CompositionResultSet result = repository.Get(key); 
      scope.Commit(); 

      MapData(); 
      return AutoMapper.Mapper.Map<ProcessSetDTO>(result); 
     } 

También tuvimos una larga discusión sobre el momento de hacer un scope.Commit y si bien no es necesaria para las consultas, se establece un patrón consistente para cada función en la capa de aplicación. Por cierto, estamos usando NCommon para nuestros patrones de repositorio/unidad de trabajo y no tenemos que pasar la UoW al repositorio.

0

Su implementación IUnitOfWork contiene todos los repositorios.

Su IUnitOfWork se inyecta en su capa de presentación como controlador mvc.

Su IUnitOfWork se inyecta en el controlador mvc.

Su IRepository se inyecta en su implementación de UnitOfWork.

Cuestiones relacionadas