1)在大多数情况下,每个Aggregate Root
应定义自己的事务边界,在这种情况下,我们不需要在IUnitOfWork
中公开Domain Layer
接口。
a)我假设在这种情况下,一个很好的选择是repository
(由aggregate
用来强制invariants
在其中应用)来包含它自己的{{1}实例1}}(如果使用EF,那么这个UoW
实例可能只是类型UoW
)?
2)
a)但是如果由于某种原因DbContext
跨越多个transaction
(因此需要一次更改多个aggregates
),那么aggregate
将不会Domain Layer
还需要包含IUnitOfWork
接口吗?
b)不会在IUnitOfWork
中暴露Domain Layer
界面违反持久性无知规则吗?
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架构师都没有将回购暴露给聚合的问题(我只是问,因为我读了几篇关于回购和DDD的文章,我得到的印象是作者不是反对暴露回购聚合 - 但现在我不再那么肯定了)?
b)所以你也反对将存储库暴露给域服务?
c)根据你的回答判断你是否认为你认为IUnitOfWork
是违反PI的?
2)Note that although my command handler (app service in a way)...
您通常将命令处理程序实现为app服务吗?
3)
public void Handle(ApproveOrderCommand command)
{
var order = Repository.Get(command.OrderId);
property.Approve(command.Comment, ServiceRequiredForOrderApproval);
Repository.Save(order);
}
property.Approve(...)
是一个拼写错误,你的意思是order.Approve(...)
?
提前完成
答案 0 :(得分: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时,我可以使用Chain of Responsibility模式撰写:
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
“装饰”它来“链接”我的命令处理程序的任何。
并且一些处理程序甚至可能触及多个存储库或聚合。但是,聚合对持久性,工作单元,交易等一无所知。
答案 1 :(得分:2)
持久性无知意味着:业务层对于在底层使用的具体持久性系统(例如MS SQL Server,Oracle,XML文件等)没有任何知识和依赖性。
因此,暴露一个抽象出数据存储的具体类型的接口永远不会违反这个原则。
答案 2 :(得分:1)
持久性无知是一个指导原则,几乎不可能用实际的语言和技术来实现。存储库模式和工作单元抽象了持久性相关的东西,并且&#34;隐藏&#34;数据访问层到业务代码,但它绝对是绝对解决方案(一个干净的技巧)。某事物的存在或需要(界面,基类,属性......)说&#34; heyyy,这里有一些我们想隐藏的东西......&#34;违反PI。但目前还没有更好的解决方案。