DDD 聚合:实体持有标识符到另一个聚合中的非根实体
DDD Aggregates: Entity holding identifier to Non-Root Entity in another Aggregate
我正在尝试了解实体和聚合之间关系的最佳实践。
想象一个设计,您有一个 产品聚合,由两个实体组成:
聚合根:产品
子实体:Sku
一个产品可以有很多 SKU。 Sku 和产品的部件号和名称是不变的,因为更改其中一个的名称必须在事务上确保另一个已更新。同样,产品聚合需要确保永远不会有重复的 Sku。
我们还有另一个 聚合:StorageLocation。存储 1 个或多个 Sku 的位置。但是,重要的是 StorageLocation 知道它正在存储的特定 Sku。 IE。加拿大的 StorageLocation 应存储该国家/地区本地的 Sku,而不是用于美国市场的 Sku。
这对我来说意味着 StorageLocation 需要保留对 Sku 的引用(因为对产品聚合根的引用本身并不能提供足够的信息来确定正在存储的 Sku)。
根据我的阅读,这似乎违反了另一个聚合不应持有对另一个聚合中的非根实体的引用的原则。所以问题:
- 在 StorageLocation 聚合中只保留产品和 Sku 的标识符是否可以接受?
- 我知道瞬态引用被认为是允许的,但在这种情况下(至少据我所知)需要存储此信息。如前所述,仅存储对产品(或 ProductId)的引用是不够的。
- 产品和 Sku 具有自然标识符(部件号、Sku 编号)。这是否为将这些值存储在 StorageLocation 聚合中提供了更大的灵活性,因为它们具有超出技术含义的意义。
- 我是不是以错误的方式处理这个问题,需要以不同的方式看待事物。我经常发现很难摆脱PK/FK的心态。
谢谢
不存储对子实体的引用的指南是建立在好的原则之上的,但我相信这经常会引起混淆。目标实际上是子实体不一定具有 'globally unique' 标识符,并且没有存储库使用这种全球唯一标识符直接访问子实体。
但是,如果您的 StorageLocation
拥有 Product
的全球唯一标识符,以及 SKU 可能的本地唯一标识符,那么以下模式没有任何问题:
var storageLocation = _storageLocationRepository.Get(id);
var product = _productRepository.Get(storageLocation.ProductId);
product.DoSomethingToSku(storageLocation.SkuId);
关键是,通过确保您始终从存储库获取产品,然后通过 产品与子实体交互,您确保产品有机会保护它自己的不变量。
总结一下:
- 只要您还存储其聚合根的全局标识符,就可以随意将标识符存储到子实体。
- 在这种情况下,子实体 ID 可以是本地唯一的或全局唯一的 - 只要通过聚合根访问子实体就没有关系。
- 切勿直接从存储库加载子实体并对其调用方法 - 因为这样聚合根就没有机会保护其不变量。
- 事实上,您甚至不应该拥有子实体的存储库
Is holding just an identifier to the Product and Sku in the StorageLocation aggregate acceptable?
是的,因为标识符在 DDD 中是值对象,将标识符存储在 StorageLocation 聚合中并不会违反持有对另一个聚合的子实体的引用的规则,因为值对象只是一个值对象,不再具有任何与原始聚合直接关联。
I'm aware that a transient reference is deemed allowable, but in this instance (at least as far as I can tell) this information needs to be stored. As mentioned, storing a reference to the Product (or ProductId) is not enough.
将 StorageLocation 聚合根脱水回数据库应该包括需要持久化的所有内容。基础设施层决定了您的域对象如何存储在物理存储库中,并且可能是与您的域模型完全不同的模型设计,具体取决于对持久性技术的关注。
Product and Skus have natural identifiers (Part Number, Sku Number). Does this provide greater flexibility for storing these values in the StorageLocation aggregate as they have meaning beyond technical implications.
没有什么可以比较 "greater flexibility" 因为您只会使用自然标识符或瞬态引用来从 StorageLocation 聚合引用 Product 聚合内的实体。
Am I approaching this the wrong way and need to look at things differently. I often find it difficult to break out of a PK / FK mindset.
请记住,持久层问题不应与域模型纠缠在一起,目的是使域模型清晰并与当前业务规则同义。
我正在尝试了解实体和聚合之间关系的最佳实践。
想象一个设计,您有一个 产品聚合,由两个实体组成:
聚合根:产品
子实体:Sku
一个产品可以有很多 SKU。 Sku 和产品的部件号和名称是不变的,因为更改其中一个的名称必须在事务上确保另一个已更新。同样,产品聚合需要确保永远不会有重复的 Sku。
我们还有另一个 聚合:StorageLocation。存储 1 个或多个 Sku 的位置。但是,重要的是 StorageLocation 知道它正在存储的特定 Sku。 IE。加拿大的 StorageLocation 应存储该国家/地区本地的 Sku,而不是用于美国市场的 Sku。
这对我来说意味着 StorageLocation 需要保留对 Sku 的引用(因为对产品聚合根的引用本身并不能提供足够的信息来确定正在存储的 Sku)。
根据我的阅读,这似乎违反了另一个聚合不应持有对另一个聚合中的非根实体的引用的原则。所以问题:
- 在 StorageLocation 聚合中只保留产品和 Sku 的标识符是否可以接受?
- 我知道瞬态引用被认为是允许的,但在这种情况下(至少据我所知)需要存储此信息。如前所述,仅存储对产品(或 ProductId)的引用是不够的。
- 产品和 Sku 具有自然标识符(部件号、Sku 编号)。这是否为将这些值存储在 StorageLocation 聚合中提供了更大的灵活性,因为它们具有超出技术含义的意义。
- 我是不是以错误的方式处理这个问题,需要以不同的方式看待事物。我经常发现很难摆脱PK/FK的心态。
谢谢
不存储对子实体的引用的指南是建立在好的原则之上的,但我相信这经常会引起混淆。目标实际上是子实体不一定具有 'globally unique' 标识符,并且没有存储库使用这种全球唯一标识符直接访问子实体。
但是,如果您的 StorageLocation
拥有 Product
的全球唯一标识符,以及 SKU 可能的本地唯一标识符,那么以下模式没有任何问题:
var storageLocation = _storageLocationRepository.Get(id);
var product = _productRepository.Get(storageLocation.ProductId);
product.DoSomethingToSku(storageLocation.SkuId);
关键是,通过确保您始终从存储库获取产品,然后通过 产品与子实体交互,您确保产品有机会保护它自己的不变量。
总结一下:
- 只要您还存储其聚合根的全局标识符,就可以随意将标识符存储到子实体。
- 在这种情况下,子实体 ID 可以是本地唯一的或全局唯一的 - 只要通过聚合根访问子实体就没有关系。
- 切勿直接从存储库加载子实体并对其调用方法 - 因为这样聚合根就没有机会保护其不变量。
- 事实上,您甚至不应该拥有子实体的存储库
Is holding just an identifier to the Product and Sku in the StorageLocation aggregate acceptable?
是的,因为标识符在 DDD 中是值对象,将标识符存储在 StorageLocation 聚合中并不会违反持有对另一个聚合的子实体的引用的规则,因为值对象只是一个值对象,不再具有任何与原始聚合直接关联。
I'm aware that a transient reference is deemed allowable, but in this instance (at least as far as I can tell) this information needs to be stored. As mentioned, storing a reference to the Product (or ProductId) is not enough.
将 StorageLocation 聚合根脱水回数据库应该包括需要持久化的所有内容。基础设施层决定了您的域对象如何存储在物理存储库中,并且可能是与您的域模型完全不同的模型设计,具体取决于对持久性技术的关注。
Product and Skus have natural identifiers (Part Number, Sku Number). Does this provide greater flexibility for storing these values in the StorageLocation aggregate as they have meaning beyond technical implications.
没有什么可以比较 "greater flexibility" 因为您只会使用自然标识符或瞬态引用来从 StorageLocation 聚合引用 Product 聚合内的实体。
Am I approaching this the wrong way and need to look at things differently. I often find it difficult to break out of a PK / FK mindset.
请记住,持久层问题不应与域模型纠缠在一起,目的是使域模型清晰并与当前业务规则同义。