骨料的C#DDD模式查询
我是DDD的新手,所以请容忍我 情景 聚合A和 骨料B A通过聚合B上的关系Id与B相关联(因此它将是B.A_Id 现在,我必须创建B,但有一条规则,如果B.SalesDate距离a.ReleaseDate的距离小于7个日历日,我就不能创建B。我的问题是关于聚合B的CommandHandler,我可以查询聚合a以获得a.ReleaseDate,这样我就可以检查提供的B.SalesDate是否小于7个日历日?这是部分CommandHandler上的代码在聚合B上的使用:骨料的C#DDD模式查询,c#,domain-driven-design,asp.net-core-webapi,C#,Domain Driven Design,Asp.net Core Webapi,我是DDD的新手,所以请容忍我 情景 聚合A和 骨料B A通过聚合B上的关系Id与B相关联(因此它将是B.A_Id 现在,我必须创建B,但有一条规则,如果B.SalesDate距离a.ReleaseDate的距离小于7个日历日,我就不能创建B。我的问题是关于聚合B的CommandHandler,我可以查询聚合a以获得a.ReleaseDate,这样我就可以检查提供的B.SalesDate是否小于7个日历日?这是部分CommandHandler上的代码在聚合B上的使用: public async
public async Task Handle(AddBCommand command, CancellationToken cancellationToken)
{
if (!command.IsValid())
{
NotifyValidationErrors(command);
return;
}
// this is where I do a query on Aggregate A to get details using the Id (which is A.Id from Aggregate A) selected on UI
var aggregateADetails = await A_Repository.GetFirstAsync(x => x.Id == command.Id);
//if (isCloserthan7Days.)
//{
// NotifyError(string.Empty, "B.SalesDate is 7 days closer than A.ReleaseDate");
// return;
//}
因此,在这个CommandHandler上,我实例化了2个存储库,1个用于B,1个用于A,以便在查询中使用。这样做会违反DDD规则吗?对不起,还不太清楚
谢谢您的命令处理程序被认为是应用程序层而不是域层 综上所述,从命令处理程序加载聚合A并将数据推送到聚合B是完全可以的,但逻辑必须在域层中实现,这意味着聚合B方法是检索域层方法执行其工作所需的所有数据。所需数据(在本例中)是否来自另一个聚合无关。从语义上讲,这与从该聚合的读取模型投影中读取属性相同,对于DDD的“规则”来说也无所谓(尽管在考虑从异步生成的投影中读取时,您应该意识到引入最终一致性问题的可能性)。需要记住的重要一点是,即使您可以从聚合A中读取,在该更改的范围内,您也应该只编辑(并保存)一个聚合 我在最初的回答中没有提到,但应该提到,康斯坦丁在评论中指出的是一致性问题可能会导致最终的一致性问题,从另一个聚合读取数据也可能会导致一致性问题,因为从聚合A读取的数据在聚合B完成操作并尝试持久化时可能已过时
(回复编辑):在您的代码示例中,您的方法是应用程序层和域层逻辑的组合。从repos加载是应用程序层,但决定您是否应在聚合中执行操作的逻辑应该属于聚合内部。我可能在这里缺少一些信息,但从我目前所看到的一点来看,我猜您可能有一个友好的域模型。不管怎样,我的初始响应仍然适用。是的,聚合A将仅用于获取A.ReleaseDate并在命令处理程序上用于验证目的,保存时的其余逻辑在域级别的聚合B上。您应该在yiur回答中添加一个重要注意事项,即此规则在最终的应用程序中被选中不一致的方式。@ConstantinGalbenu也许我不是很清楚,应该为此更新答案,但我不是建议使用异步生成的读取模型。我只是说加载聚合来读取值在行为和语义上与从投影读取类似。@Skleanthu是的,我知道,但是使用其他聚合数据的业务规则(如“应该”)最终是一致的,开发人员必须意识到这一点。架构(经典或CQR)是不相关的。@ConstantinGalbenu是的,你是对的。我将修改答案。