开发者

Generic repository factory and service composition

In previous question folks helped me to solve repository lifetime problem, now there's a question how to make it work nicely in composite service.

let's say i have services:

public class OrderService : IOrderService 
{         
     IRepository<Order> orderRepository;          

     public OrderService(IRepositoryFactory repositoryFactory) 
     {
        orderRepository = repositoryFactory.GetRepository<Order>();
     }

     public void CreateOrder(OrderData orderData) 
     {
        ...
        orderRepository.SubmitChanges();
     }
}

public class ReservationService : IReservationService 
{
     IRepository<Reservation> reservationRepository;

     public ReservationService(IRepositoryFactory repositoryFactory) 
     {
        reservationRepository = repositoryFactory.GetRepository<Reservation>();
     }

     public void MakeReservations(OrderData orderData)   
     {
         ...
         reservationService.SubmitChanges();
     }
}

And now the intersting part - composition service:

public class CompositionService : ICompositionService {
     IOrderService orderService;
     IReservationService reservationService;

     public CompositionService(IOr开发者_如何学JAVAderService orderService, IReservationService reservationService) 
     {
        this.orderService = orderService;
        this.reservationService = reservationService;
     }

     public void CreateOrderAndMakeReservations(OrderData orderData) 
     {
        using (var ts = new TransactionScope()) 
        {
           orderService.CreateOrder(orderData);
           reservationService.MakeReservations(orderData);
           ts.Complete();
        }
     }
}

Problem is, that it won't work correctly if IRepositoryFactory lifestyle is transient (because you would get two different datacontexts and that would require distributed transactions to be enabled, which we try to avoid). Any ides how to write this correctly?


My observations:

  1. In general, factories should be singletons. If your factory isn't a singleton, then you are probably just hiding another factory behind it.
  2. Factories are meant for creating objects on demand. Your code simply creates a repository in the constructor, so I don't really see the difference between that and simply making the repository a direct injection parameter in the constructor.

These all seem to me like a workarounds around a more fundamental problem (described in your first question) and these workarounds only make the problem more complicated. Unless you solve the root problem you will end up with a complex dependency schema and a smelly code.


IMO - this is a Distributed Transaction scenario.

In the example you mentioned, OrderService & ReservationService use the same data context is an implementation detail hidden in the code.

I don't think it is correct to pass this knowledge up to the CompositionService by wrapping the service calls in a TransactionScope as now the composition service is aware of the shared data context & so needs to use a TransactionScope to run the code correctly.

In my opinion, the composition service code should look like:

try{
 if(orderService.TryCreateOrder(orderData)){
   if(reservationService.TryMakeReservation(orderData)){
      reservationService.Commit();
      orderService.Commit();
   }
   else{
     orderService.TryRollbackOrder(orderData);
     throw new ReservationCouldNotBeMadeException();
   }
 }
 else{
  throw new OrderCouldNotBeCreatedException();
 }
}
catch(CouldNotRollbackOrderServiceException){
 // do something here...
}
catch(CouldNotCommitServiceException){
 // do something here...
}

In this case, the OrderService.TryCreateOrder method will insert an Order with a PendingReservation status or some other relevant status which indicates that the Order is inserted, but not completed. This state will change on the commits are called on the services (UnitOfWork pattern?)

In this case, the implementation details of the services are completely hidden from the consumer of the service, while composition is also possible, independent on the underlying implementation detail.

HTH.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜