【问题标题】:DDD and references between aggregates in EFCore and C#EFCore 和 C# 中的聚合之间的 DDD 和引用
【发布时间】:2019-03-02 22:29:54
【问题描述】:

我有一个问题,我不确定在假设 DDD 并使用 C#/EF Core 时如何解决。

简化情况:我们有 2 个聚合 - ItemWarehouse。它们中的每一个都通过 ExternalId(Guid) 来标识它的身份(FE 等),这也被视为其域身份。它还具有在数据库模型中标识它的 database Id - 实体模型和 Db 模型与 EF Core 允许使用私有字段的类相同 - 只有 ExternalId 和必需的字段被公开。实体(在 DDD 和 EF Core 意义上)包含大量与对象严格耦合的业务逻辑和方法。一般来说,我遵循eShop/eShopOnContainers 示例中的模式。

项目被分配给仓库,当创建一个项目时,我们需要将仓库传递给它的构造函数。

将完整的 Warehouse 对象传递给 Item 的构造函数是否合适(也可以传递给 Item 定义的其他方法):

public Item(Warehouse warehouse,..)

或者我应该只转发数据库 ID:

public Item(long warehouseId,..)

我对此有一个问题,因为一方面我读到聚合不应该引用其他聚合,但另一方面,使用数据库数据库会将实现细节(关系数据库中的对象持久性)泄漏到不应该的域模型在我看来发生。

使用 ExternalId:

public Item(Guid warehouseId,..)

不能解决问题,因为 db 中的实际关系不基于它。

你的意见是什么?我有点疑惑。

【问题讨论】:

  • 有时有两套模型会派上用场:领域模型和持久模型:)

标签: c# entity-framework-core domain-driven-design


【解决方案1】:

通常您会为聚合根的 ID 创建一个值对象。依赖数据库生成的 Id 是一种可能性。如果您决定让 Db 生成 Id,那么您将需要使用它。 但是,为什么您仍然需要传递 Warehouse 引用或 Id 呢?看起来 Item 是一个实体,而 Warehouse 是应该包含该实体的聚合根。一般来说,您不应该在聚合根之外创建实体。

编辑: Vaughn Vernon 在红皮书中描述了几种身份创建策略。其中之一是让 SQL Db 等持久化机制生成实体或聚合的唯一标识符。

【讨论】:

  • 上图只是简化的。它们都需要是聚合根。该项目需要分配一个仓库。
  • @user1658223 如果它们确实都是聚合根,那么您可能只需要warehouseId,因为您在“事务边界”中有重叠的地方。 AR 应该只能通过它自己的 Id 访问,并且绝对不应该依赖于构造函数中的其他一些 aggregateRootId,因为这意味着你只能在有仓库的情况下创建一个 Item。
  • 好的。忘记给出的例子。让我们假设仓库不是由构造函数传递,而是通过 Item 的方法:AssignToWarehouse。我应该通过 Warehouse 还是 WarehouseId?
  • 为什么?为什么直接引用它们的缺点是?
  • 好的。几乎被说服了,但只传递一个 id 会泄露对域来说应该是透明的数据库 ID。
【解决方案2】:

您在分析期间创建的域模型通常与在设计期间创建的域模型不同。从语义上讲,它们都是相同的,您正在传递引用,但设计模型认识到您必须保留数据,因此出于性能原因您可能不想预加载所有引用的对象,无论这是否只是从磁盘中加载它同一个域,或者来自另一个域中的远程服务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多