聚合根能否引用其他聚合根?采购订单与商品的DDD界定疑问
Great questions—these are super common when wrapping your head around DDD aggregates, especially when dealing with cross-domain or multi-app scenarios. Let’s break them down one by one:
Short answer: Yes, but not by holding the entire aggregate object—you reference them by their ID.
Here’s why: Aggregates exist to define clear consistency boundaries. If one aggregate root held a direct reference to another full aggregate, you’d cross those boundaries, making it exponentially harder to enforce transactional consistency (you don’t want a change to a Supplier accidentally breaking a Purchase Order, right?).
Instead, you store the ID of the related aggregate root. For example, a PurchaseOrder AR might have a list of ItemIds or SupplierIds, not the full Item or Supplier objects. When you need the actual data for that related aggregate, you’d fetch it via a repository or service outside the current aggregate’s logic.
Also, remember that interactions between aggregates should usually happen via domain events or orchestrated by an application service, not by one aggregate directly modifying another. That keeps each aggregate focused on its own core responsibilities.
This is a perfect example of why bounded context and independent lifecycle matter so much in DDD. The short answer here is absolutely—Items should be their own Aggregate Root.
Let’s break down the reasoning:
- Items have their own independent lifecycle: They’re created, edited, and managed in a separate app with no required ties to Purchase Orders. That means they need their own consistency boundary to protect attributes like brand, designer, color, and type from conflicting changes.
- If you tried to nest Items under the PurchaseOrder aggregate, you’d force an unnecessary dependency. The Item management app would have to adhere to the PurchaseOrder aggregate’s rules, which doesn’t make sense for its standalone use case.
- For the PurchaseOrder side of things, you don’t need the full Item object—just its ID and maybe snapshot data (like the price at the time of order) to maintain the order’s consistency. The PurchaseOrder aggregate only cares about which items are being ordered and their order-specific details, not the Item’s internal state.
In your SOA setup, this aligns perfectly with bounded contexts: the Item management app lives in its own bounded context with the Item AR, while the Purchase Order app operates in another context, referencing Items by ID. This keeps each system decoupled and able to evolve independently without stepping on each other’s toes.
内容的提问来源于stack exchange,提问作者Ish Thomas

