DDD - 在不更新整个聚合根的情况下更新实体的小细节
DDD - Update a small detail on an Entity without updating the whole Aggregate Root
假设我的 AggregateRoot 是 Order-模型。有一个包含 OrderItems(实体)的集合。
我只有一个 Repository 用于 AggregateRoot(订单),但没有用于 OrderItems。
当客户只想更新一个小的更改,例如一个 OrderItem 上的 Remarks 字段时,我该怎么办?
我目前的理解是客户端通过DTO发送更新。然后中间件加载整个订单,然后更新单个细节,并将整个订单提交到存储库。
如果我理解正确的话,那是现实生活中的一个好习惯,还是你有不同的处理方式?这听起来对我来说性能不佳且维护不友好。
正如 DDD 中的所有内容一样,答案在于域规则。一切都必须围绕规则而不是数据结构。
警告:下面的示例过于简单!
您必须更改一个订单项的Remarks字段,所以请教您一个问题:Remarks字段更改操作有哪些限制和不变量? OrderItem 是否具有为此所需的所有信息?如果是,那么在这种情况下 OrderItem 是您的聚合根。
是否有一些备注不允许进入订单项,因为它属于某种类型的订单,但其他订单类型允许此备注。那么Order就是你的聚合根。
这为您提供了有关如何处理它的线索,但是因为您的评论加载一个包含所有 OrderItems 的订单只是为了更改一个 OrderItem Remark 是绝对不高效的。
“I’m sorry that I coined the term ‘objects,’ because it gets many
people to focus on the lesser idea. The big idea is ‘messaging’” ~
Alan Kay
还记得我说过 DDD 必须强调环绕规则而不是环绕数据结构吗?
所以,不要考虑数据结构。围绕命令和事件(消息)和规则对所有事物进行建模。让你的持久性存储库为该命令带来适当的聚合根,使用 AR 应用命令,return 一个域事件产生的变化,并使用该事件来持久化新的系统状态并通知其他服务有关变化.
来自
的代码示例
class ApplicationService{
public void registerUser(RegisterUserCommand registerUserCommand){
var user = new UserEntity(registerUserCommand.userData); //avoid wrong entity state; ctor. fails if some data is incorrect
RegistrationAggregate agg = aggregatesRepository.Handle(registerUserCommand); //handle is overloaded for every command we need. Use registerUserCommand.tenantId to bring total_active_users and quota from persistence, create RegistrarionAggregate fed with TenantData
var userRegisteredEvent = agg.registerUser(user); //return domain changes expressed as a event
persistence.Handle(userRegisteredEvent); //handle is overloaded for every event we need; open transaction, persist userRegisteredEvent.fromTenant.total_active_users where tenantId, optimistic concurrency could fail if total_active_users has changed since we read it (rollback transaction), persist userRegisteredEvent.user in relationship with tenantId, commit transaction
eventBus.publish(userRegisteredEvent); //notify external sources for eventual consistency
}
这允许您从持久性中将 OrderItemRemarkManagerAggregate 带入内存,其中仅包含更改备注所需的信息(即 OrderItem ID、当前备注、OrderItem 状态、所属的 OrderType 等);只需使用它来应用操作并将更改应用到持久性中。
稍后您可能会担心为多个操作重用聚合(当然总是在同一个限界上下文中)或者甚至根据需要进行重构。
假设我的 AggregateRoot 是 Order-模型。有一个包含 OrderItems(实体)的集合。 我只有一个 Repository 用于 AggregateRoot(订单),但没有用于 OrderItems。
当客户只想更新一个小的更改,例如一个 OrderItem 上的 Remarks 字段时,我该怎么办?
我目前的理解是客户端通过DTO发送更新。然后中间件加载整个订单,然后更新单个细节,并将整个订单提交到存储库。
如果我理解正确的话,那是现实生活中的一个好习惯,还是你有不同的处理方式?这听起来对我来说性能不佳且维护不友好。
正如 DDD 中的所有内容一样,答案在于域规则。一切都必须围绕规则而不是数据结构。
警告:下面的示例过于简单!
您必须更改一个订单项的Remarks字段,所以请教您一个问题:Remarks字段更改操作有哪些限制和不变量? OrderItem 是否具有为此所需的所有信息?如果是,那么在这种情况下 OrderItem 是您的聚合根。
是否有一些备注不允许进入订单项,因为它属于某种类型的订单,但其他订单类型允许此备注。那么Order就是你的聚合根。
这为您提供了有关如何处理它的线索,但是因为您的评论加载一个包含所有 OrderItems 的订单只是为了更改一个 OrderItem Remark 是绝对不高效的。
“I’m sorry that I coined the term ‘objects,’ because it gets many people to focus on the lesser idea. The big idea is ‘messaging’” ~ Alan Kay
还记得我说过 DDD 必须强调环绕规则而不是环绕数据结构吗? 所以,不要考虑数据结构。围绕命令和事件(消息)和规则对所有事物进行建模。让你的持久性存储库为该命令带来适当的聚合根,使用 AR 应用命令,return 一个域事件产生的变化,并使用该事件来持久化新的系统状态并通知其他服务有关变化.
来自
class ApplicationService{
public void registerUser(RegisterUserCommand registerUserCommand){
var user = new UserEntity(registerUserCommand.userData); //avoid wrong entity state; ctor. fails if some data is incorrect
RegistrationAggregate agg = aggregatesRepository.Handle(registerUserCommand); //handle is overloaded for every command we need. Use registerUserCommand.tenantId to bring total_active_users and quota from persistence, create RegistrarionAggregate fed with TenantData
var userRegisteredEvent = agg.registerUser(user); //return domain changes expressed as a event
persistence.Handle(userRegisteredEvent); //handle is overloaded for every event we need; open transaction, persist userRegisteredEvent.fromTenant.total_active_users where tenantId, optimistic concurrency could fail if total_active_users has changed since we read it (rollback transaction), persist userRegisteredEvent.user in relationship with tenantId, commit transaction
eventBus.publish(userRegisteredEvent); //notify external sources for eventual consistency
}
这允许您从持久性中将 OrderItemRemarkManagerAggregate 带入内存,其中仅包含更改备注所需的信息(即 OrderItem ID、当前备注、OrderItem 状态、所属的 OrderType 等);只需使用它来应用操作并将更改应用到持久性中。
稍后您可能会担心为多个操作重用聚合(当然总是在同一个限界上下文中)或者甚至根据需要进行重构。