DDD,域实体/ VO和JPA

Eri*_*ron 15 java spring domain-driven-design jpa spring-data-jpa

我从DDD开始,你可以想象我的大脑沸腾了.

我的问题与我的域对象(实体,VO,...)有关,它代表我的域概念/逻辑以及如何持久/检索它们.

蓝皮书说,存储库是一种表示域对象集合的方式,负责与基础架构层进行通信.我在一些帖子中也读到了infrastructura层,你必须使用hibernate,JPA或其他什么.

然后我看到这个Spring-data-jpa示例http://spring.io/guides/gs/accessing-data-jpa/我变得疯狂.

该口号称Spring-data-jpa是为了轻松创建存储库,之前的示例似乎将JPA注释合并到域对象(the customer)中.

样品对吗?或者我是对的?

如果我是对的,域和基础设施必须分开,这意味着要存储我必须拥有的客户:

  • Customer我的域层中的一个类(代表一个客户并具有所有逻辑操作)
  • 一个CustomerRepository未经我的领域层(从基础设施层检索或存储客户)
  • Customer基础结构层中的类,可能使用@Entity注释
  • 有些人CustomerReposityJPA知道如何从数据库中存储/检索客户.

谢谢你的任何澄清.

小智 12

在DDD中,存储库是参与域的对象,但实际上是抽象出一些后备存储.

如果使用JPA注释注释域对象,则持久性机制已渗入您的域.您已将域结构绑定到持久性结构,这是不理想的.

您的JpaCustomerRepository(实现ICustomerRepository)可以将未注释的域类(Customer)映射到带注释的JPA表示 - JPA客户.这样可以将注释保留在域类之外,因此更清晰.它允许您独立于域结构改变JPA持久性结构.这种好处的代价是映射代码的复杂性.

interface ICustomerRepository {}

class JpaCustomerRepository implements ICustomerRepository {
     void save(Customer customer) {
          JpaCustomer jpaCustomer = map(customer);
          save(jpaCustomer);
     }
}

class Customer {}

class JpaCustomer {}
Run Code Online (Sandbox Code Playgroud)

  • “成本高,存在重复代码”——如果 DDD Customer 与愚蠢的 JPA Customer 实体相同,那么就是重复代码。但 DDD Customer 应该是一个具有真实行为的对象,而不是像 JPA 实体那样的假对象(通常只包含字段 + getter/setter + ORM 注释)。 (4认同)
  • 成本很高,代码重复:需要映射属性的两个客户类.听起来像很多样板代码.JPA提供商的替代品有多大可能证明额外的努力是正确的? (3认同)
  • 我认为JPA Annotations是声明性信息.如果您需要替换JPA提供程序,从域实体中删除JPA注释有多难? (2认同)

BAD*_*EED 3

我看不到您发布的链接,而且我从未将域驱动设计应用于 Java 世界。理论上你需要的是Customer在领域层聚合。在您的域层中,有存储库的空间(用作接口),因此您将拥有ICustomerRepository. 对于常见的持久性问题,您可能会有四个原型:

GetById(CustomerId id);
Add(Customer c);
Delete(Customer c);
Update(Customer c);
Run Code Online (Sandbox Code Playgroud)

在基础设施层中,您将提供主体(例如CustomerRepository),在基础设施层中,您可以将自己与技术结合起来(例如 JPA)。

域层必须完全不知道基础设施中使用的技术。这样做你可以完全改变实现细节,(几乎)没有任何麻烦。