Domain driven design 如何使用DDD处理更新实体(CRUD)和域事件?

Domain driven design 如何使用DDD处理更新实体(CRUD)和域事件?,domain-driven-design,cqrs,domain-events,anemic-domain-model,dddd,Domain Driven Design,Cqrs,Domain Events,Anemic Domain Model,Dddd,我知道DDD很适合基于任务的UI,但我正在重构一个遗留应用程序,我的领域模型很差(许多setter没有业务逻辑) 第一步是使其到达模型并添加域事件。在为创建(TaskCreated在构造函数中)和删除(TaskRemoved)模型添加事件是一个简单的过程,但我正在努力更新模型 我们有一个带有PUT/tasks/{id}端点的RESTful API。框架将响应主体映射到DTO对象,然后逐个调用setter: task.setText('new text'); task.setStartDate(n

我知道DDD很适合基于任务的UI,但我正在重构一个遗留应用程序,我的领域模型很差(许多setter没有业务逻辑)

第一步是使其到达模型并添加域事件。在为创建(
TaskCreated
在构造函数中)和删除(
TaskRemoved
)模型添加事件是一个简单的过程,但我正在努力更新模型

我们有一个带有PUT
/tasks/{id}
端点的RESTful API。框架将响应主体映射到DTO对象,然后逐个调用setter:

task.setText('new text');
task.setStartDate(newStartDate);
// and so on
我想在任务更新时听到一些事件,并在谷歌日历中更新它。 正如你所想象的那样,如果我在每个
setter
(TextChanged,StartDateChanged)中记录事件并监听所有这些事件,我最终会得到许多对谷歌API的API调用,这不是我想要的

问题是:我应该如何以正确的方式处理更新操作?我是否应该用一个
update(newData)
调用替换所有那些
setter
调用,并在那里只发送一个域事件?如何在任务更新后只对google日历进行一次API调用

我应该如何以正确的方式使用更新操作

通常的答案是,域事件不是要修改的对象的一部分,而是在单独的数据结构中描述修改

对于贫血模型,我希望来电者对事件负责。如果框架只是将DTO字段自动映射到任务,那么这可能不是框架。您希望在代码中理解编辑的业务上下文的某个点定义事件。换句话说,您可能希望重新安排任务,而不是更新任务

在初稿中,您可以在知道保存成功时发布事件

更可靠的方法是将事件列表与任务一起保存。这为您提供了关于可靠消息传递的更好的故事-请参阅Udi Dahan,以更好地了解这一趋势


如果域模型不是贫血的,那么您确实可以在任务更新中定义事件(数据模型中的事件仍然与任务状态分开)。

我更喜欢一个事件一个事件一个事件的方式,因为更新操作有时只是一个用例,想象一下,您将不得不在域的稍后部分,由于外部过程,只更改实体的一个字段,您应该有一个表示该用例的命令,而不是整个更新

现在问题来了:我如何跟踪基于单个用例触发的事件?简单地说,使用某种相关标识符,例如可以是请求Id


为了实现这一点,您可以使用一个包含域事件的列表,当您保存事务时,您可以分派事件,并且由于它们是在相同的逻辑上下文中创建的,它们将具有相同的关联Id。

“对于非贫血的域模型,您确实可以在任务更新中定义事件。”非贫血模型的代码是什么?我的意思是如何同时实际更新几个字段,这是否是一个好主意?我对这里的细节了解不够,无法判断您答案的技术质量。但是你想减少一点文字墙的印象吗?在这里和那里使用换行符。也许可以创建更短、更容易阅读的句子。