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

发布于 2024-11-03 08:12:47 字数 1815 浏览 3 评论 0原文

上一个问题中,人们帮助我解决了存储库生命周期问题,现在有一个问题如何让它在组合服务中很好地工作。

假设我有服务:

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 生活方式是瞬态的,它将无法正常工作(因为您将获得两个不同的数据上下文,并且需要启用分布式事务,我们需要启用分布式事务)尽量避免)。有什么想法如何正确写这个吗?

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一江春梦 2024-11-10 08:12:47

我的观察:

  1. 一般来说,工厂应该是单例的。如果您的工厂不是单例,那么您可能只是在其后面隐藏了另一个工厂。
  2. 工厂用于按需创建对象。您的代码只是在构造函数中创建一个存储库,因此我并没有真正看到它与简单地将存储库作为构造函数中的直接注入参数之间的区别。

在我看来,这些都是围绕更基本问题(在第一个问题中描述)的解决方法,而这些解决方法只会使问题变得更加复杂。除非你解决根本问题,否则你最终会得到一个复杂的依赖模式和臭代码。

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.

撩动你心 2024-11-10 08:12:47

IMO - 这是一个分布式事务场景。

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

我认为通过将服务调用包装在 TransactionScope 中来将这些知识传递给 CompositionService 是不正确的,因为现在组合服务知道共享数据上下文和数据。因此需要使用 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。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文