Java 更新集合时休眠删除孤儿

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1304862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 08:02:10  来源:igfitidea点击:

Hibernate deleting orphans when updating collection

javahibernateorphan

提问by Marty Pitt

I'm finding that orphan records aren't being deleted when removing from a collection in Hibernate. I must be doing something simple wrong, (this is Hibernate-101!), but I can't find it..

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

Given the following:

鉴于以下情况:

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

And the following update code:

以及以下更新代码:

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

AuthorDAO snippet:

AuthorDAO 片段:

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

The following test the fails:

以下测试失败:

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!

In summary, I'm finding:

总之,我发现:

  • While book is removed from the Author's collection of books, it still exists in the database
  • If I examine book.getAuthor().getBooks(), book does not exist in that collection
  • 虽然 book 从作者的书籍收藏中删除,但它仍然存在于数据库中
  • 如果我检查book.getAuthor().getBooks(),该集合中不存在这本书

This "feels" like I'm not flushing the session or forcing an update appropriately - but I'm not sure where I should be doing that. Along that vein, other points that may be impacting:

这“感觉”就像我没有刷新会话或适当地强制更新 - 但我不确定我应该在哪里这样做。沿着这条脉络,其他可能会影响的点:

  • I'm performing the above in a JUnit test decorated with @RunWith(SpringJUnit4ClassRunner.class)
  • I originally hit this problem inside an update routine which is decorated with @Transactional, however, I have since recreated it in a plain old JUnit test.
  • 我在装饰有的 JUnit 测试中执行上述操作 @RunWith(SpringJUnit4ClassRunner.class)
  • 我最初在一个用 修饰的更新例程中遇到了这个问题@Transactional,但是,我已经在一个普通的旧 JUnit 测试中重新创建了它。

Any advice would be greatly appreciated!

任何建议将不胜感激!

EDIT:Thanks for all the feedback already. Further to comments below, I've added the @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)to the parent, so it's now:

编辑:感谢您的所有反馈。除了下面的评论之外,我已经将 加到@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)了父级,所以现在是:

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

I'm still finding the same results. I MUST be missing something simple.

我仍然在寻找相同的结果。我一定错过了一些简单的东西。

采纳答案by cletus

You're not doing anything wrong. You're just not removing the child entity. You can either do this with an explicit remove() of the child entity (in addition to what you're doing) or use that annotation that causes orphan records to be deleted.

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

Also, it's worth mentioning that CascadeType.DELETEwon't delete orphans either. That means something else. See JPA CascadeType.ALL does not delete orphans.

此外,值得一提的是,CascadeType.DELETE也不会删除孤儿。那是别的意思。请参阅JPA CascadeType.ALL 不删除孤儿。

Basically to do this automatically you'll want this on the collection in the parent:

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

org.hibernate.annotations.CascadeType.DELETE_ORPHAN

回答by JARC

Try using the following annoation if you want 'transitive dependency' behavour.

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

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

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

回答by Sindri Traustason

The cascade option in the @OneToManyannotation is a array, what you want is:

@OneToMany注解中的cascade选项是一个数组,你要的是:

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

回答by Am1rr3zA

please add @onDelete maybe this work for you

请添加@onDelete 也许这对你有用

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

回答by Civil Disobedient

Looks like you're might be missing the mappedByannotation. Try:

看起来您可能缺少mappingBy注释。尝试:

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

回答by Jakub

for people searching for their solution: Now in Hibernate, resp. JPA 2.0, this is the right way:

对于寻找解决方案的人:现在在 Hibernate 中,resp。JPA 2.0,这是正确的方法:

@OneToMany(orphanRemoval=true)

回答by Sanjeev Dhiman

I know I'm late to the party and I realize a lot has been said already on this topic but IMHO I would not use delete-orphans as a cascade option. I would rather delete child associations manually before deleting the parent. One slight oversight... and a long chain of associations can be deleted in a second. Yes! I agree that this may be exactly one would want in some circumstances.

我知道我迟到了,我意识到关于这个话题已经说了很多,但恕我直言,我不会使用删除孤儿作为级联选项。我宁愿在删除父级之前手动删除子级关联。一个轻微的疏忽……一长串关联可以在一秒钟内删除。是的!我同意在某些情况下这可能正是人们想要的。