Hibernate在更新集合时删除孤立

时间:2009-08-20 08:48:01

标签: java hibernate orphan

我发现从Hibernate中的集合中删除时不会删除孤立记录。我必须做一些简单的错误,(这是Hibernate-101!),但我找不到它..

鉴于以下内容:

public class Book {
    @ManyToOne
    @NotNull
    Author author;
}
public class Author
{
    @OneToMany(cascade={CascadeType.ALL})
    List<Book> books;
}

以下更新代码:

Author author = authorDAO.get(1);
Book book = author.getBooks().get(0);
author.getBooks().remove(0);
authorDAO.update(author);

AuthorDAO代码段:

@Override
public void update(T entity) {
    getSession().update(entity);
}

以下测试失败:

Author author = author.get(1);
assertEquals(0,author.getBooks().size()); // Passes
Book dbBook = bookDAO.get(book.getId())
assertNull(dbBook); // Fail!  dbBook still exists!
assertFalse(author.getBooks().contains(dbBook) // Passes!

总之,我发现:

  • 虽然书籍从作者的书籍集中删除,但它仍然存在于数据库中
  • 如果我检查book.getAuthor().getBooks(),该集合中不存在该书

这种“感觉”就像我没有冲洗会话或强制更新 - 但我不知道我应该在哪里做。沿着这条路线,可能会影响的其他方面:

  • 我在用@RunWith(SpringJUnit4ClassRunner.class)
  • 装饰的JUnit测试中执行上述操作
  • 我最初在一个用@Transactional修饰的更新例程中遇到了这个问题,但是,我已经在一个普通的旧JUnit测试中重新创建了它。

非常感谢任何建议!

编辑:感谢所有反馈意见。在下面的评论中,我已将@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)添加到父级,现在就是:

public class Author
{
    @OneToMany(cascade={CascadeType.ALL})
    @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    List<Book> books;
}

我仍然找到相同的结果。我必须遗漏一些简单的东西。

7 个答案:

答案 0 :(得分:41)

搜索他们解决方案的人:现在在Hibernate,resp。 JPA 2.0,这是正确的方法:

@OneToMany(orphanRemoval=true)

答案 1 :(得分:19)

你没有做错任何事。你只是没有删除子实体。您可以使用子实体的显式remove()(除了您正在执行的操作)执行此操作,也可以使用导致孤立记录删除的注释。

此外,值得一提的是CascadeType.DELETE也不会删除孤儿。这意味着别的东西。见JPA CascadeType.ALL does not delete orphans.

基本上,为了自动执行此操作,您需要在父级的集合中使用它:

org.hibernate.annotations.CascadeType.DELETE_ORPHAN

答案 2 :(得分:3)

@OneToMany注释中的级联选项是一个数组,您想要的是:

@OneToMany(cascade={CascadeType.ALL, CascadeType.DELETE_ORPHAN})

答案 3 :(得分:0)

如果您想要“传递依赖”行为,请尝试使用以下注释。

@ org.hibernate.annotations.Cascade(CascadeType.DELETE_ORPHAN)

答案 4 :(得分:0)

请为你添加@onDelete这项工作

public class Author
{
    @OneToMany(cascade={CascadeType.ALL})
    @OnDelete(action = OnDeleteAction.CASCADE)
    @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    List<Book> books;
}

答案 5 :(得分:0)

您可能会错过 mappedBy 注释。尝试:

public class Book {
  @ManyToOne
  @NotNull
  Author author;
}
public class Author {
  @OneToMany(mappedBy="author", cascade={CascadeType.ALL})
  List<Book> books;
}

答案 6 :(得分:0)

我知道我参加聚会很晚,并且我知道在这个主题上已经讲了很多话,但是恕我直言,我不会使用delete-orphans作为级联选项。我宁愿在删除父级之前手动删除子级关联。一秒钟的疏忽...和一长串的关联可以在一秒钟内删除。是!我同意在某些情况下这可能恰好是我们想要的。