【问题标题】:Problem with aggregate root with more than one value object of the same type具有多个相同类型的值对象的聚合根问题
【发布时间】:2021-08-25 07:34:22
【问题描述】:

我是 Spring Data JDBC 的新手,我使用 Spring-Boot 2.5.0、Java 11 和 Lombok(简化的代码示例)创建了一个包含两个 Address 值的 Customer 聚合。

我有一个客户实体(聚合根)和一个地址值对象

@Data
@Builder
@AllArgsConstructor
class Customer {
    @Id Long id;
    String name;
    Address address1;
    Address address2;
}

@Data
@Builder
@AllArgsConstructor
class Address {
    String city;
}

和一个客户实体的存储库

@Repository
public interface CustomeRepository extends CrudRepository<Customer, Long> {
}

使用 Postgres 的 db 架构如下所示

CREATE TABLE "customer" (
  "id"                  BIGSERIAL       NOT NULL,
  "name"                VARCHAR(255)    NOT NULL,
  PRIMARY KEY (id)
);

CREATE TABLE "address" (
  "id"                  BIGSERIAL       NOT NULL,
  "customer"            BIGINT,
  "city"                VARCHAR(255)    NOT NULL,
  PRIMARY KEY (id)
);

创建和存储客户

        var address1 = Address.builder().city("New York").build();
        var address2 = Address.builder().city("Chicago").build();
        var customer = Customer.builder().name("Joe").address1(address1).address2(address2).build();
        var result = customerRegistry.save(customer);

到目前为止一切都很好,数据库中的条目看起来也很好

 id | name 
----+------
  1 | Joe


 id | customer |   city   
----+----------+----------
  1 |        1 | Chicago
  2 |        1 | New York

所以期待一位客户,但这样做时

var customers = customerService.findAll();
customers.forEach(c -> log.debug("Customer: {}", c));

输出将是

Customer(id=1, name=Joe, address1=Address(city=New York), address2=Address(city=Chicago))
Customer(id=1, name=Joe, address1=Address(city=Chicago), address2=Address(city=Chicago))
Customer(id=1, name=Joe, address1=Address(city=New York), address2=Address(city=New York))
Customer(id=1, name=Joe, address1=Address(city=Chicago), address2=Address(city=New York))

然后这样做

var customer = customerRepository.getById(result.getId());

会导致

org.springframework.dao.IncorrectResultSizeDataAccessException: Incorrect result size: expected 1, actual 4

顺便说一句。如果客户只有一个地址字段,一切都会按预期进行。

所以我错过了什么还是这是一个错误?

【问题讨论】:

    标签: java postgresql spring-boot spring-data spring-data-jdbc


    【解决方案1】:

    您可以将@Column 注释放在一个或两个属性上,指定用于反向引用Customer 的不同列。

    例如:

    class Customer {
        @Id Long id;
        String name;
        @Column("first")
        Address address1;
        @Column("second")
        Address address2;
    }
    

    期望以下address

    CREATE TABLE "address" (
      "id"                  BIGSERIAL       NOT NULL,
      "first"               BIGINT,
      "second"              BIGINT,
      "city"                VARCHAR(255)    NOT NULL,
      PRIMARY KEY (id)
    );
    

    如需了解更多背景信息和超出当前特定问题的其他替代方案,请参阅Why is a entity - value relationship implemented as a back reference in Spring Data JDBC

    【讨论】:

    • 您好 Jens,非常感谢您的快速回复!实际上,我使用 Map 之类的地图来表示三种不同的地址类型。它工作正常,但我认为你的建议是更好的解决方案。来自弗伦斯堡的感谢和问候,Stefan
    • 第一和第二列应该在客户表还是地址表中?
    • @Gaurav 在地址表中
    • 确切的地址将存储在哪里,我正在考虑将第一个和第二个作为地址 ID
    • @Gaurav 对不起,我不明白你的问题。 address 中的 id 不是必需的,我建议不要这样做。 firstsecond 的组合是独一无二的。
    猜你喜欢
    • 1970-01-01
    • 2018-02-28
    • 2021-05-28
    • 2020-06-20
    • 2020-12-21
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多