Spring 存储库 saveAll 为映射实体插入重复行
Spring repository saveAll inserting duplicate rows for mapped entity
我正在尝试插入与另一个实体具有一对一关系的实体列表。对于许多父实体,一对一映射对象可能是相同的。我期望在父实体的外键中引用相同的子实体,但实际上正在创建重复的行。这是我的实体。
@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 都与其帐户一起创建,这些帐户可能具有完全相同的信息,但实时对象不同。
当我这样做时:
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会有两行table,Account会有一行,结果发现Account也有两行。看起来 Equals 和 HashCode 在这种情况下没有任何效果。
当映射对象与 equals/hashcode 相似时,如何处理此问题以不插入重复行。
JPA 对 @EqualsAndHashcode
不执行任何操作(仅生成 class 方法 equals
和 hashCode
)。
JPA 通过用 @Id
(或 @EmebeddedId
)注释的实体 id 来识别实体,这个 id 也是可以实现和检查的东西——通常也会生成(比如一些数据库序列)——在数据库级别。
如果你想在 JPA 端使用由 name
和 accountId
标识的 Account
,你需要使用 @EmbeddedId
和 @Embeddable
并摆脱@Id
。这将是这样的:
@Embeddable
public class AccountId {
String name;
String accountId; // maybe needs renaming...
}
然后在 Account
:
@EmbeddedId
AccountId accountId;
我正在尝试插入与另一个实体具有一对一关系的实体列表。对于许多父实体,一对一映射对象可能是相同的。我期望在父实体的外键中引用相同的子实体,但实际上正在创建重复的行。这是我的实体。
@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 都与其帐户一起创建,这些帐户可能具有完全相同的信息,但实时对象不同。
当我这样做时:
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会有两行table,Account会有一行,结果发现Account也有两行。看起来 Equals 和 HashCode 在这种情况下没有任何效果。
当映射对象与 equals/hashcode 相似时,如何处理此问题以不插入重复行。
JPA 对 @EqualsAndHashcode
不执行任何操作(仅生成 class 方法 equals
和 hashCode
)。
JPA 通过用 @Id
(或 @EmebeddedId
)注释的实体 id 来识别实体,这个 id 也是可以实现和检查的东西——通常也会生成(比如一些数据库序列)——在数据库级别。
如果你想在 JPA 端使用由 name
和 accountId
标识的 Account
,你需要使用 @EmbeddedId
和 @Embeddable
并摆脱@Id
。这将是这样的:
@Embeddable
public class AccountId {
String name;
String accountId; // maybe needs renaming...
}
然后在 Account
:
@EmbeddedId
AccountId accountId;