这个问题可能是由于我对JPA可以做什么和不能做什么的无知,所以希望有人能够启发我。简而言之,从集合中删除实体不会传播到其祖父母的内存实例。以下是一个示例场景。
我们有三个实体(A、B、C)。
@Entity
public class C {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
...
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name="B_ID")
private B b;
...
}
和,
@Entity
public class B {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@OneToMany(mappedBy = "b", fetch = FetchType.EAGER, cascade = {CascadeType.REMOVE, CascadeType.MERGE})
private Set<C> cs;
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "A_ID")
private A a;
...
}
和,
@Entity
public class A {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@OneToMany(mappedBy = "tenant", fetch = FetchType.EAGER, cascade ={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
private Set<B> bs;
...
}
接下来,我们有一个用于修改 B 实例的无状态会话 bean。
@Stateless
public class BServiceBean implements BService {
@PersistenceContext(unitName = Constants.PU)
EntityManager em;
@Override
public B updateB(B b) {
return em.merge(b);
}
@Override
public B removeC(int bId, int cId) throws IllegalArgumentException {
B b = em.find(B.class, bId);
if (null == b) {
throw new IllegalArgumentException("No b with id: " + bId + " exists.");
}
C c = em.find(C.class, cId);
if (null == c) {
throw new IllegalArgumentException("No c with id: " + cId + " exists.");
}
b.getCs().remove(c);
em.remove(c);
return em.merge(b);
}
}
我们通过容器注入的 BService 实例在 servlet 中修改这些实体。
// created and persisted an A with three Bs, one of which has three Cs.
A a = ...;
b2.setName(changedName);
b2 = bService.updateB(b2); // this change is reflected in a
...
b2 = bService.removeC(b2.getId(), c1.getId()); // this change is not reflected in a
// but it is in the db
a = aService.findAById(a.getId); // this instance of a has a b2 without a c1
为什么从 B 中的集合中删除实体不会在合并到 A 时级联,即使 B 中基本字段的更改确实会在 B 合并时级联到 A?我能做些什么来使 JPA 将实体删除向上级联到 A 吗?