【问题标题】:Exposing IUnitOfWork interface in Domain Layer violates Persistence Ignorance rule?在域层中暴露 IUnitOfWork 接口违反了持久性无知规则?
【发布时间】:2014-01-04 04:37:16
【问题描述】:

1) 在大多数情况下,每个Aggregate Root 都应该定义自己的事务边界,在这种情况下,我们不需要在Domain Layer 中公开IUnitOfWork 接口。

a) 我认为在这种情况下,一个不错的选择是repository(由aggregate 使用以强制在其中应用invariants)包含它自己的UoW 实例(如果使用EF,那么这个UoW 实例可能只是DbContext 类型)?

2)

a) 但是如果出于某种原因transaction 跨越多个aggregates(因此需要一次更改多个aggregate),那么Domain Layer 不会也需要包含IUnitOfWork 接口?

b) 在Domain Layer 中暴露IUnitOfWork 接口不会违反持久性无知规则

c) 如果 b) 是肯定的,那么暴露IUnitOfWork 是否会破坏拥有repositories 的目的?

回复 Alexey Raga:

1) I would advice against exposing repositories to aggregates. Repositories are there to give you aggregates, that's it.

a) 虽然我认为大多数 ddd 架构师在将 repos 暴露给聚合时没有问题(我只是问,因为我阅读了几篇关于 repos 和 DDD 的文章,我得到的印象是作者不是反对将存储库暴露给聚合 - 但现在我不再那么确定了)?

b) 所以您也反对将存储库暴露给域服务?

c) 从您的回答来看,我猜您认为将IUnitOfWork 公开为违反 PI?

2)Note that although my command handler (app service in a way)...

您通常将命令处理程序实现为应用服务吗?

3)

public void Handle(ApproveOrderCommand command)
{
    var order = Repository.Get(command.OrderId);
    property.Approve(command.Comment, ServiceRequiredForOrderApproval);
    Repository.Save(order);
}

property.Approve(...) 是不是一个错字,而你的意思是 order.Approve(...)

提前感谢

【问题讨论】:

  • 将 IUnitOfWork 接口作为域的一部分不一定是坏事,就像将存储库接口作为域的一部分也不是坏事一样。只要它们与您的实现完全分开。
  • @stephenl:存储库的目的是抽象出持久性。但是 IUnitOfWork 接口本身不是一个持久性细节,因此通过在域层中引入它,我们将持久性细节泄漏到域层中吗?
  • 该接口实际上并没有实现任何东西,因此将其保留在域中是可以的。该接口的实现可能会有所不同,具体取决于您使用的后端存储,因此应该在您的域之外。
  • 并非如此。对您的问题的一些回答已经比我更好地回答了这个问题。另一方面,鉴于当今大多数 ORM 已经为您实施变更跟踪,我想知道是否甚至需要 IUoW。如果您删除实现更改跟踪的方法,您只是真正提交或回滚事务,这不一定需要作为单独的模式。还是这样?
  • 碰巧Jimmy Bogard 刚刚写了一篇关于这个的博客。见lostechies.com/jimmybogard/2013/12/20/…

标签: domain-driven-design unit-of-work persistence-ignorance


【解决方案1】:

我建议不要将存储库暴露给聚合。存储库可以为您提供聚合,仅此而已。

这样看:您的域是一个“泡沫”,它只了解自己的东西。意思是,它只了解它自己的值对象、它声明的域服务接口等。我不会在这个集合中包含存储库。

当您的域(聚合)需要某些东西时,它应该显式公开它所需要的依赖项,而不仅仅是请求某个存储库。

服务将事物结合在一起。 例如,我的命令处理程序可能如下所示:

public class ApproveOrderCommandHandler  : IHandle<ApproveOrderCommand> 
{
    //this might be set by a DI container, or passed to a constructor
    public IOrderRepository Repository { get; set; }
    public ISomeFancyDomainService ServiceRequiredForOrderApproval { get; set; }  

    public void Handle(ApproveOrderCommand command)
    {
        var order = Repository.Get(command.OrderId);
        order.Approve(command.Comment, ServiceRequiredForOrderApproval);
        Repository.Save(order);
    }
}

请注意,尽管我的命令处理程序(某种方式的应用服务)处理存储库,但我的域(订单聚合)对持久性一无所知。它对 UnitOfWorks 的存储库一无所知。

当我确实需要启动 UnitOfWork 时,我可以使用责任链模式组合它:

public class WithUnitOfWorkHandler<T> : IHandler<T>  {
    private readonly IHandler<T> _innerHandler;

    public WithUnitOfWorkHandler(IHandler<T> innerHandler)  {
        _innerHandler = innerHandler;
    }

    public void Handle(T command) {
        using(var ouw = new UnitOfWork()) {
            _innerHandler.Handle(command);
            uow.Commit();
        }
    }
}

现在我可以通过使用WithUnitOfWorkHandler“装饰”我的命令处理程序“链接”任何。 并且一些处理程序甚至可能涉及多个存储库或聚合。尽管如此,聚合对持久性、工作单元、事务等一无所知。

【讨论】:

  • 感谢您的回答。你能回复我的回复吗?
  • 我按要求回复。 a) 没有“DDD 警察”,显然你可以做任何你想做的事,我只是认为将存储库暴露给 domain(不仅是聚合)是不合逻辑的。 IMO 域应以域语言显式声明其依赖项,而不是某些存储库。 b) 通常是的,因为它们是域的一部分并且使用域语言。为他们提供了依赖项。 c) 不是真的,因为UnitOfWork 和存储库实现不在域“内部”,所以域保持 PI。
  • 2) 通常是的,我查看命令处理程序就像在我的应用程序服务中一样,因为任何 action 都是某个命令的结果。 3)是的,这是一个错字。我复制粘贴并忘记更改名称:)
  • 我知道我的回复迟了,但我刚刚注意到 ApproveOrderCommandHandler 实现了 IHandle 而 WithUnitOfWorkHandler 实现了 IHandler。这是一个错字吗?实际上 ApproveOrderCommandHandler 和 WithUnitOfWorkHandler 都实现了相同的接口(即 IHandler )?
【解决方案2】:

持久性无知意味着:业务层不知道也不依赖于在后台使用的具体持久性系统(例如 MS SQL Server、Oracle、XML 文件等)。

因此,公开一个抽象出数据存储具体类型的接口永远不会违反这一原则。

【讨论】:

  • 我认为即使在域或服务层中公开 UoW 接口也违反了 PI,因为 UoW 接口包含与持久性相关的语言,因此以某种方式与持久性相关的细节泄露到服务/域层(虽然我知道这两层对具体的 UoW 实现一无所知)
【解决方案3】:

持久性无知是一种指导方针,用实际的语言和技术几乎不可能达到。存储库模式和工作单元抽象了与持久性相关的东西并将数据访问层“隐藏”到业务代码中,但它更像是一个技巧(一个干净的)而不是一个绝对的解决方案。某些东西(接口、基类、属性......)的存在或需要说“嘿,这里有一些东西我们想隐藏......”违反了 PI。但目前没有更好的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多