3

1)在大多数情况下,每个都Aggregate Root应该定义自己的事务边界,在这种情况下,我们不需要IUnitOfWorkDomain Layer.

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

2)

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

IUnitOfWorkb) 暴露接口不会Domain Layer违反持久性无知规则吗?

c) 如果b)是,那么暴露IUnitOfWork的目的不就失败了repositories吗?

回复阿列克谢·拉加:

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

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

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(...)

提前感谢

4

3 回答 3

2

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

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

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

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

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。并且一些处理程序甚至可能涉及多个存储库或聚合。尽管如此,聚合对持久性、工作单元、事务等一无所知。

于 2013-12-18T13:36:48.107 回答
2

Persistence ignorance 意味着:业务层对底层使用的具体持久性系统(例如 MS SQL Server、Oracle、XML 文件等)一无所知,也没有任何依赖关系。

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

于 2013-12-21T14:30:35.753 回答
1

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

于 2015-04-16T06:52:45.827 回答