java - Spring data - 具有相同标识符的不同对象,即使对象相等
问题描述
我有一个使用 spring boot 2.2.6 构建的项目,我正在尝试在数据库中插入/更新一个条目(Parent)并对其子级进行级联 de 操作,如果子级不存在,则应该插入它,否则应该是更新。我有以下课程:
@Entity
@Data
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
List<Child> children1;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
List<Child> children2;
}
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(of = {"id"})
public class Child {
@Id
private Long id;
private String name;
}
public interface ParentRepository extends JpaRepository<Parent, Long> {
}
@Service
public class TestService {
private ParentRepository parentRepository;
public TestService(ParentRepository parentRepository) {
this.parentRepository = parentRepository;
}
@Transactional
public void save() {
Parent parent = new Parent();
Child c1 = new Child(1L, "c1");
Child c2 = new Child(1L, "c1");
List<Child> children1 = new ArrayList<>();
children1.add(c1);
List<Child> children2 = new ArrayList<>();
children1.add(c2);
parent.setChildren1(children1);
parent.setChildren2(children2);
parentRepository.save(parent);
}
}
我没有任何其他配置,因此我收到以下错误:
A different object with the same identifier value was already associated with the session : [Child#1]
我不明白为什么我会收到此错误,因为 c1.equals(c2) 被评估为真。
如果我将 children1 和 children2 的类型更改为 Set,我会收到以下错误:
Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.CHILD(ID) [1, 'c1']"
现在我不明白为什么会收到此错误,因为我期望合并级联类型来处理此问题,进行更新而不是插入。
你能帮我理解我错过了什么吗?你能给我一些关于在这种情况下插入/更新对象的最佳实践的提示吗?
解决方案
尽管 Java 中的对象相等,但这并不意味着它们在持久化上下文中是同一个实体。一旦你这样做:
Child c1 = new Child(1L, "c1");
Child c2 = new Child(1L, "c1");
...并使用PERSIST
级联将它们持久化,这两个对象都将被持久化,并且由于它们的 ID 相等,因此违反了唯一 ID 约束。解决方案是使用相同的对象,因此实体只会被创建一次:
Child c = new Child(1L, "c1");
List<Child> children = new ArrayList<>();
children.add(c);
parent.setChildren1(children);
parent.setChildren2(children);
推荐阅读
- r - 如何使用 R 中的线索对数据集进行排序
- tcpdf - tcpdf 中的图像完全不适合 pdf
- algorithm - 找到最小生成树成本的最佳方法
- flask - 无法使用 Apache-Superset 应用程序一次连接两个 LDAP 服务器
- javascript - 当事件循环阻止应用程序进行 I/O 操作时?
- c# - 为什么将整数转换为 ASCII 然后再转换为整数后会得到不同的值?
- java - 有没有办法与 Hot Publisher 并行运行多个订阅者。- Reactive java
- javascript - 未检测到魔术头文件已使用这些加载程序处理:* ./node_modules/wasm-loader/index.js
- google-apps-script - 在 Google Apps 脚本中定义 BigQuery 表位置
- ssis - SSIS 查找转换无匹配输出仅填充 Null