【问题标题】:Identity conflict in DDD with RepositoryDDD 与存储库中的身份冲突
【发布时间】:2012-12-29 14:21:57
【问题描述】:

我在示例应用程序中遵循数据库优先方法。 POCO 类是通过 t4 模板生成的,它将具有它从数据库中携带的 Identity 属性。对于我在域中用作实体的某些类,id 的 type 可以是 int, string & Guid

我没有看到我可以在域中生成并将其传递给存储库的字符串或 Guid 的问题。在 int 的情况下,我也可以这样做,但我想利用 SQL 数据库的 AUTOINCREMENT 选项

我的问题是:

  1. 谁负责为实体生成身份。是域还是存储库?

  2. 如何在存储库和域之间同步身份?例如,我可以为域中的 Customer 创建一个 id 为 1000 的 ID,并请求 Repository 保存它。当存储库保存它时,新标识可能是 2000(AUTOINCREMENT 选项设置新标识)。现在这两个实体是不同的,如果域中的 Customer 实体(假设它被缓存以供将来操作)与 Department 等其他实体一起使用,则可能会导致域中的问题。 id 为 1000 的域中的缓存实体 (Customer) 将作为新实体保存在 SQL 数据存储中。存储库不知道客户是缓存的还是新的。

【问题讨论】:

    标签: .net domain-driven-design ddd-repositories


    【解决方案1】:

    谁负责为实体生成身份。是吗 域还是存储库?

    实体的身份可以由域直接分配或通过客户端请求分配。这种类型的身份通常使用Guid 或其他通用唯一值生成。身份也可以由存储库分配以反映数据库生成的身份,例如增量身份列。

    如何在存储库和存储库之间完成身份同步 域名?

    当实体的身份来自数据库生成的身份列时,域不应分配自己的身份。具有完整身份的临时实体最初将具有身份值 0。当临时实体成为持久实体时,存储库将分配身份值。那时,正如您所指出的,由于身份值已更改,因此新持久实体实例的缓存实例可能存在一些问题。有几种方法可以解决这些问题,但我尽量避免首先引用缓存(或其他任何地方)中的瞬态实体。这可以通过确保一个实体在持久化之前不会在很多地方被引用来更容易地完成。如果你最终在不同的地方引用了一个临时实体实例,你可以确保它的 .NET 运行时标识在实例的生命周期内保持不变。为此,您必须在身份值检查之前通过object.ReferenceEquals 比较实体,并且必须在对象生命周期内缓存通过GetHashCode 生成的哈希码。

    【讨论】:

    • 要评论您的第一个答案,我从未遇到过用户这样的问题域,“我想要一长串随机但唯一的字符,以便我可以识别每个 [实体]。”我的观点是 Guid 不需要在域中定义。如果您有跨多个服务器或类似性质的同步需求,则将域实体包装在处理此问题的基础设施对象中会更好。但是,支持您对第二个问题的回答。说得好。我会赞成它。
    • 用户通常根本不关心 ID,而 Guid 的好处是它可以由调用客户端提供,在这种情况下它不需要等待来自服务器知道创建的实体的 ID。这在 CQRS 场景中很有用。另一个优点是在服务器提供 ID 的情况下,无需等待数据库响应即可知道 ID。无论哪种方式,ID 都是一个技术问题。
    • 我同意 ID 是一个技术问题,那么为什么要使用不符合您的通用语言的 ID 污染您的域模型(应该独立于技术问题)?你给出的两个例子都可以轻松解决,没有这种不必要的烟雾。
    • 那么如何解决客户提供实体 ID 有利的情况呢?或者是否希望在没有数据库往返的情况下生成身份?
    • 鉴于唯一的要求是客户端生成 ID,应用服务将具有接受 ID 以及用于构建聚合的信息(或 DTO)的方法。但是,如果域代码需要在客户端上执行(从未见过这种情况),那么客户端就像存储库一样,无论它是否仅将聚合存储在内存中。在这种情况下,我将有一个客户端存储库 impl。这将在 ID 存储在服务器上之前跟踪 ID 以及聚合(即哈希表或包装类)。
    猜你喜欢
    • 2015-12-21
    • 2012-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    相关资源
    最近更新 更多