通用存储库工厂和服务组合

时间:2011-04-27 12:06:01

标签: c# castle-windsor ioc-container

previous question人帮助我解决了存储库生存期问题,现在有一个问题是如何使它在复合服务中很好地工作。

假设我有服务:

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();
     }
}

现在有趣的部分 - 作曲服务:

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

     public CompositionService(IOrderService 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();
        }
     }
}

问题是,如果IRepositoryFactory生活方式是暂时的(因为您将获得两个不同的datacontexts并且需要启用分布式事务,我们会尽量避免),它将无法正常工作。任何想法如何正确写这个?

2 个答案:

答案 0 :(得分:1)

我的观察:

  1. 一般来说,工厂应该是单身人士。如果你的工厂不是单身,那么你可能只是隐藏了另一家工厂。
  2. 工厂用于创建按需对象。您的代码只是在构造函数中创建了一个存储库,所以我并没有真正看到它之间的区别,只是简单地将存储库作为构造函数中的直接注入参数。
  3. 在我看来,这些都是围绕更基本问题的解决方法(在您的第一个问题中描述),这些解决方法只会使问题更加复杂。除非你解决根问题,否则你最终会得到一个复杂的依赖模式和一个有臭味的代码。

答案 1 :(得分:1)

IMO - 这是一个分布式事务方案。

在您提到的示例中,OrderService&amp; ReservationService使用相同的数据上下文是隐藏在代码中的实现细节。

我认为通过在TransactionScope中包装服务调用将此知识传递给CompositionService是不正确的,因为现在组合服务已知道共享数据上下文&amp;所以需要使用TransactionScope正确运行代码。

在我看来,合成服务代码应如下所示:

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...
}

在这种情况下,OrderService.TryCreateOrder方法将插入一个具有PendingReservation状态的订单或一些其他相关状态,指示订单已插入但未完成。这个状态会在服务上调用提交(UnitOfWork模式?)

在这种情况下,服务的实现细节完全隐藏在服务的使用者之外,而组合也是可能的,独立于底层实现细节。

HTH。