如何表达向存储库添加聚合根?
假设我们有一个Order类型的聚合根实体,它关联客户和订单行.当我考虑一个订单实体时,将其概念化为没有Id的定义更为自然.没有Id的订单似乎更好地表示为订单请求而不是订单.
要向存储库添加订单,我通常会看到人们在没有Id的情况下实例化订单,然后让存储库完成对象: class OrderRepository { void Add(Order order) { // Insert order into db and populate Id of new order } } 我喜欢这种方法的是你将Order实例添加到OrderRepository.这很有道理.但是,订单实例没有Id,并且在存储库的使用者的范围内,对我来说,订单没有Id也没有意义.我可以将OrderRequest定义为订单的实例并将其添加到存储库,但这感觉就像从橙色中导出苹果然后将其添加到橙色列表中. 或者,我也看到过这种方法: class OrderRepository { Order AddOrder(Customer customer) // It might be better to call this CreateOrder { // Insert record into db and return a new instance of Order } } 我喜欢这种方法的是没有Id的订单是未定义的.存储库可以创建数据库记录并在创建和返回订单实例之前收集所有必需的字段.这里有什么味道,你实际上从未向存储库添加订单实例. 无论哪种方式都有效,所以我的问题是:我是否必须接受这两种解释中的一种,或者是否有最佳实践来模拟插入? 我发现这个答案类似,但对于价值对象: 解决方法
我想首先排除第二种方法.它不仅看起来违反直觉,而且还违反了一些好的设计原则,例如
Command-Query Separation和
Principle of Least Surprise.
其余选项取决于域逻辑.如果域逻辑规定没有ID的订单没有意义,则ID是Order的必需不变量,我们必须对其进行建模: public class Order { private readonly int id; public Order(int id) { // consider a Guard Clause here if you have constraints on the ID this.id = id; } } 请注意,通过将id字段标记为只读,我们已将其设为不变量.我们无法为给定的Order实例更改它.这完全符合Domain-Driven Design的实体模式. 您可以通过将Guard子句放入构造函数来进一步强制执行域逻辑,以防止ID为负或零. 到目前为止,您可能想知道这可能如何与数据库中自动生成的ID一起使用.嗯,事实并非如此. 没有好办法确保提供的ID尚未使用. 这有两个选择: >将ID更改为Guid.这允许任何呼叫者为新订单提供唯一ID.但是,这要求您也使用Guids作为数据库键. 在许多情况下,创建新订单是一种在任何情况下都需要特定建模的业务操作,因此我认为没有问题可以做出这种区分.尽管Order和OrderRequest在语义上可能非常相似,但它们甚至不必在类型层次结构中相关. 我甚至可能会说它们不应该相关,因为OrderRequest是一个Value Object而Order是一个实体. 如果采用这种方法,AddOrder方法必须返回Order实例(或至少ID),否则我们无法知道刚创建的订单的ID.这导致我们回到CQS违规,这就是为什么我倾向于选择Guids for Entity ID. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- Oracle第二天
- Flash 之ANE的applicationDeployment.nativeLibrary ...
- 正则表达式,返回特定字母后面的数字,直到下一个字母
- IE下flash总是置于最前
- 数据结构与算法(十五):二叉排序树
- c# – 使用JNI AndroidJNI.GetMethodID与字符串参数统一
- iphone – 在Xcode中,我是否在构建或版本下输入我的应用程序
- c# – 异常越过Application.ThreadException和AppDomain.Cu
- 监控flash_recovery_area的使用情况
- ruby-on-rails – Rails link_to破坏嵌套资源?