我有以下实体:
@Entity
public static class Parent {
@Id
@GeneratedValue
private Long id;
String st;
@OneToMany(mappedBy = "parent")
Set<Child> children = new HashSet<>();
// get,set
}
@Entity
public static class Child {
@Id
@GeneratedValue
private Long id;
String st;
@ManyToOne()
private Parent parent;
//get,set
}
请注意,@ OneToMany端没有Cascade。
我想要以下内容:
我执行了一些调试,发现子集合是PersistentSet,它记住了storedSnapshot中的状态。因此,当我将Parent合并到上下文时--Hibernate会对存储的快照执行某些操作并尝试从DB加载child。当然,没有这样的实体,抛出异常。
所以,我可以做几件事:
但它似乎是一个黑客。
所以, 1.我做错了什么?看来,直接删除子实体是正确的 2.有更优雅的方式来处理这个问题吗?
可重复的例子:
@Autowired
PrentCrud parentDao;
@Autowired
ChiildCrud childDao;
@PostConstruct
public void doSomething() {
LogManager.getLogger("org.hibernate.SQL").setLevel(Level.DEBUG);
Parent p = new Parent();
p.setSt("1");
Child e = new Child();
e.setParent(p);
e.setSt("c");
p.getChildren().add(e);
Parent save = parentDao.save(p);
e.setParent(save);
childDao.save(e);
Parent next = parentDao.findAll().iterator().next();
next.setSt("2");
next.getChildren().size();
childDao.deleteAll();
next.getChildren().clear();
if (next.getChildren() instanceof PersistentSet) { // this is hack, not working without
((Map)((PersistentSet) next.getChildren()).getStoredSnapshot()).clear();
}
parentDao.save(next); // exception is thrwn here without hack
System.out.println("Success");
}
答案 0 :(得分:0)
您是否尝试过将抓取类型更改为急切?关系的默认值
OneToMany: LAZY
ManyToOne: EAGER
ManyToMany: LAZY
OneToOne: EAGER
可能因为获取方法而被缓存
答案 1 :(得分:0)
您可以使用next.setChildren(new HashSet<>());
代替next.getChildren().clear();
来摆脱getStoredSnapshot()).clear()
但使用cascade和orphanRemoval会更优雅。
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
Set<Child> children = new HashSet<>();
public void doSomething() {
...
next.setSt("2");
next.setChildren(new HashSet<>());
parentDao.save(next);
System.out.println("Success");
}