我是 DDD 的新手,我正在尝试找出一种使用 PUT 动词来更新聚合的方法。
如果聚合中的所有属性都有私有(private) setter ,那么很明显我需要为每个业务需求设置一组功能。举个例子
supportTicket.Resolve();
我很清楚,我可以使用诸如 /api/tickets/5/resolve
之类的端点来实现这一点,但是如果我想提供一种自动更新整个票证的方法怎么办?
例如,用户可以使用以下主体向 /api/tickets/5
发出 PUT 请求
{"status" : "RESOLVED", "Title":"Some crazy title"}
我需要在 ApplicationSercvice 中做这样的事情吗
if(DTO.Status != null && dto.Status == "RESOLVED")
supportTicket.Resolve();
if(DTO.Title != null)
supportTicket.setNewTitle(DTO.title);
如果是这种情况,并且更改工单标题有一些业务逻辑可以防止在工单已解决时更改它,我是否应该在更新聚合时考虑某种优先级排序,或者我的看法完全错误?
最佳答案
Domain Driven Design for RESTful Systems -- 吉姆·韦伯
what if i want to provide a way to update whole ticket atomically?
如果您想以原子方式更新整个工单,请放弃聚合;如果您真正想要的是具有 CRUD 语义的键值存储,那么聚合是您框中的错误工具。
聚合只有在它们是要执行的域的业务规则时才有意义。当您只需要一把铲子时,不要制造拖拉机。
As an example, user can make a PUT request to /api/tickets/5
那会弄得一团糟。在 CRUD 实现中,通过向资源发送新状态的表示来替换资源的当前状态是合适的。但这根本不适合聚合,因为聚合的状态不受您(客户/发布者)的控制。
更合适的习惯用法是将消息发布到总线上,当域处理该消息时,会产生实现您想要的更改的副作用。
PUT /api/tickets/5/messages/{messageId}
现在您的应用程序服务会查看消息,并向聚合发送命令
if(DTO.Status != null && dto.Status == "RESOLVED")
supportTicket.Resolve();
if(DTO.Title != null)
supportTicket.setNewTitle(DTO.title);
这没关系,但在实践中更常见的是使消息明确说明要做什么。
{ "messageType" : "ResolveWithNewTitle"
, "status" : "RESOLVED"
, "Title":"Some crazy title"
}
甚至...
[
{ "messageType" : "ChangeTitle"
, "Title" : "Some crazy title"
}
, { "messageType" : "ResolveTicket"
}
]
基本上,您希望为应用提供足够的上下文,以便它可以进行真正的消息验证。
let's say I had aggregates which encapsulated needed business logic, but besides that there is a new demand for atomic update functionality and I am trying to understand a best way to deal with this.
因此,处理此问题的正确方法首先是在领域级别上进行处理——与您的领域专家坐下来,确保每个人都理解需求以及如何使用通用语言等来表达需求。
在聚合根中实现您需要的任何新方法。
一旦您的用例在域中得到正确支持,您就可以开始担心您的资源是否遵循之前的模式 - 资源只接收传入的请求,并调用适当的命令。
关于c# - 通过 REST 进行 DDD 更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37890512/