【问题标题】:Spring repository saveAll inserting duplicate rows for mapped entitySpring存储库saveAll为映射实体插入重复行
【发布时间】:2021-07-08 10:32:42
【问题描述】:

我正在尝试插入与另一个实体具有一对一关系的实体列表。对于许多父实体,一对一映射对象可能是相同的。我期望在父外键中引用相同的子实体,但实际上正在创建重复的行。这是我的实体。

@Builder
@Entity
   public class PaymentInfoType1 {
        @Id
        Long id;
        LocalDate date;
        @Column(precision = 15, scale = 2)
        BigDecimal amount;
        String reference;
        @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
        @JoinColumn(name = "account", referencedColumnName = "id")
        Account account;
    }

    @Builder
    @Entity
    @EqualsAndHashCode(onlyExplicitlyIncluded = true)
    public class Account {
        @Id
        Long id;
        @EqualsAndHashCode.Include
        String name;
        @EqualsAndHashCode.Include
        String accountId;
    }

我正在根据从不同系统收到的信息创建 PaymentInfoType1 列表。每个 PaymentInfoType1 都与它的 Account 一起创建,它可能具有完全相同的信息,但实时的对象不同。

当我这样做时:

PaymentInfoType1 first = // Created with some logic
Account account1 = // name = sample & accountId = 123
first.setAccount(account1);

PaymentInfoType1 second = // Created with some logic
Account account2 = // name = sample & accountId = 123
second.setAccount(account2);

// Both the above its own account object but the field have exactly same values.

List<PaymentInfoType1> list = List.of(first, second);
repo.saveAll(list);

我原以为 PaymentInfoType1 表中会有两行,Account 中会有一行,但发现 Account 也有两行。看起来 Equals 和 HashCode 在这种情况下没有任何作用。

当映射对象通过 equals/hashcode 相似时,如何处理以不插入重复行。

【问题讨论】:

    标签: java hibernate jpa spring-data-jpa lombok


    【解决方案1】:

    JPA 对 @EqualsAndHashcode 不做任何事情(只生成类方法 equalshashCode)。

    JPA 通过用@Id(或@EmebeddedId)注释的实体 id 来识别实体,而且这个 id 也是可以在数据库级别实现和检查的——通常也可以生成(如一些 db 序列)。

    如果您想在 JPA 端使用由nameaccountId 标识的Account,您需要使用@EmbeddedId@Embeddable 并去掉@Id。这将是这样的:

    @Embeddable
    public class AccountId {
        String name;
        String accountId; // maybe needs renaming...
    }
    

    然后在Account:

    @EmbeddedId
    AccountId accountId;
    

    this for example

    【讨论】:

    • 谢谢 pirho。我累了,但有一个例外:具有相同标识符值的不同对象已与会话相关联。我猜在第一次插入后,第二次插入由于主键约束而失败。我可以以某种方式保存列表并让休眠进行合并吗?
    • 这是最有可能绝对正确的错误。它告诉您,在同一个会话中创建和保存具有相同 id 值的这种 second 实体是没有意义的。相反,您应该只将 first 用于两个帐户,因为您具有一对一的关系,因此没有任何意义。
    • 我必须自己检查对象是否相同,并在父实体中设置相同的对象。这些值是从不同的系统中挑选出来的,除了我在创建新对象之前检查自己是否相同之外,没有其他方法。
    • 好吧,无论如何,没有理由阻止在逻辑的另一端同时使用 equals 和 hashcode。只有您需要将 @EqualsAndHashcode 添加到可嵌入对象中,并且在 account中仅将该嵌入标识 (accountId) 包含到您的 lombok @EqualsAndHashCode
    猜你喜欢
    • 2021-09-22
    • 2020-02-06
    • 1970-01-01
    • 2018-11-25
    • 1970-01-01
    • 1970-01-01
    • 2014-04-14
    • 2018-03-30
    • 2011-03-13
    相关资源
    最近更新 更多