【问题标题】:JPA / Hibernate removing "child" entitiesJPA / Hibernate 删除“子”实体
【发布时间】:2012-10-30 18:03:50
【问题描述】:

我有两个实体类A和B,分别以双向一对多关系存在。

A.java:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "aId",
           fetch=FetchType.EAGER, orphanRemoval=true)
private Set<B> bCollection = new LinkedHashSet<B>();

B.java

  @JoinColumn(name = "A_ID", referencedColumnName = "ID", nullable=false)
  @ManyToOne(optional = false)   
  private A aId;

在一个简单的控制台应用程序中,我从数据库中获取了一个特定的 A 行,并尝试删除其中一个详细的 B 行(随机)但 JPA /Hibernate 不仅删除该行 - 它甚至不向数据库发出任何 DELETE 语句。删除 B 行的唯一方法是从 A.java 的集合 (LinkedHashSet) 中删除相应的实体。所以,虽然我有一个解决方法,但我想了解为什么下面的代码会失败,并且也会悄悄地失败!

public static void main(String[] args) {
    EntityManagerFactory entityManagerFactory =  Persistence.createEntityManagerFactory("testjpa");
    EntityManager em = entityManagerFactory.createEntityManager();
    EntityTransaction entityTransaction = em.getTransaction();
    entityTransaction.begin();
    A a = em.find(A.class, 1);
    B b = getARandomChildOfA(a);
    em.remove(em.merge(b));     // simple em.remove(b) doesn't work either
    entityTransaction.commit();
    em.close();
    entityManagerFactory.close();
}

【问题讨论】:

    标签: hibernate jpa


    【解决方案1】:

    JPA 不会为您管理关系,因此当您在 b 上调用 remove 时,a 仍然有对它的引用。由于引用设置了级联持久/合并,它会导致 b 在上下文中复活,撤消删除。

    您必须维护引用以使您的模型与数据库中的所需内容保持同步。除非您确定可以处理此类潜在的不一致,否则最好将要删除的对象的引用清空并设置回指针。

    【讨论】:

    • 如果可以的话,请澄清一下:(1)复活发生在哪个呼叫中,有什么办法可以看到吗? (用于测试)(2)我不能总是使用 EntityManager::remove 方法来删​​除“顶级”对象(即未出现在其他对象集合中的对象)及其整个图形吗? (3) 我对“对要删除的对象的引用无效并设置回指针”的措辞感到有些困惑。我所做的是从 A 的集合中删除 B 并将 B::aId 设置为 null。你指的是这个吗?不过,取消 B:aId 似乎是多余的。这是由 JPA 规范规定的吗?
    • 复活很可能发生在提交上,因为那是应该进行更改的时候。 2)不确定你的意思。您可以删除任何实体,但您必须像管理任何 java 对象一样管理对它的任何引用。 3)我的意思是对已删除对象的引用无效。从树上修剪它们并将它们移除
    • @Chris 拯救了我的一天!谢谢克里斯。与您在第二段中描述的情况完全相同。 Cascade.remove FTW :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-22
    • 2019-07-09
    • 1970-01-01
    • 2011-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多