JPA 实体和 DDD 实体应该相同 类 吗?

Should JPA entities and DDD entities be the same classes?

根据 DDD 有 类 个实体,有 类 个有 @javax.persistence.Entity 注释。它们应该相同 类 吗?或者 JPA 实体是否应该充当映射器 (https://martinfowler.com/eaaCatalog/dataMapper.html) 从数据库加载 DDD 实体(并存储它们)并保留在域模型之外的机制?

如果数据库元数据被分离并存储在外部(例如,在 XML 中),会有什么不同吗?如果这样的类是实体,边界在哪里?我认为从 XSD(例如,使用 JAXB)或者甚至使用 MyBatis 生成器从数据库生成的 类 不是 DDD 中理解的实体。

您的 JPA 实体应该是域实体。为什么? 您的域实体应该表达一些强约束,例如通过

  • 具有参数化构造函数
  • 不公开所有 setter
  • 对写入操作进行验证

如果可能,域实体应始终保持有效的业务实体。 通过引入某种映射器,您引入了一种可能性,可以自动将任意内容写入您的域实体,这基本上会使您的约束变得无用。

另一种选择是对引入冗余的 JPA 和域实体实施相同的约束。

您最好的选择是让您的 JPA 实体尽可能与 ORM 无关。使用 Hibernate,这可以通过配置 class 或 XML 文件来完成。但是我不是JavaEE/JPA的人,所以很难给出好的实施建议。

这确实是一个实现细节。它们可能是也可能不是,这取决于您的 ORM 的灵活性。例如,如果您的 ORM 允许映射您的域对象而不会因持久性问题而污染它们,那么这就是需要较少开销的方法,我会选择这种方法。

另一方面,如果您的 ORM 不够灵活,那么您可以采用实用的混合方法,其中您的 AR 和它的状态是两种不同的 classes 并且状态 class很简单,很容易被映射。请注意,AR 仍将负责保护它在此处的状态,并且不会直接从 AR 外部访问状态对象。该方法由 Vaughn Vernon here.

描述

在使用 JPA 和微服务获得更多经验后,我会说在使用 JPA 时我很可能不会将它们分开,除非有理由让我不这样做。另一方面,单个限界上下文中的实体不一定必须只是 JPA 实体。可以使用其他技术(如 JSON 映射器)或手动使 JPA 实现映射实体和从 DTO 映射实体。

我同意这两种方式都是可行的。在使用 DDD 编写一些应用程序之后,我发现这种启发式方法很有效:

  • 如果您从拥有一个实体开始,但没有 JPA,那么重构一个实体使其可以被 ORM 框架使用可能会太难,因此请将它们分开
  • 如果你从头开始,不值得区分 DDD 实体和 JPA 实体