Hibernate如何正确删除@OneToMany中的孩子?
Posted
技术标签:
【中文标题】Hibernate如何正确删除@OneToMany中的孩子?【英文标题】:Hibernate How to correctly delete children in @OneToMany? 【发布时间】:2014-10-23 15:59:20 【问题描述】:我有一个非常简单的单向@OneToMany,从父对象到 CascadeType.ALL 的子对象列表。我将如何正确删除和删除其中一个孩子?
只需在 List 上调用 remove(child) 然后 session.saveOrUpdate(parent) 当然不起作用,并且除非我指定孤儿删除,否则不会在数据库中删除子项。
作为孤立删除的替代方法,如果我 session.delete(child) 在数据库中删除它,然后从列表中删除(child) 并且我必须 session.refresh(parent) 所以是否正确我在内存中的父对象有正确的状态?
我如何正确删除子项并将其从数据库中删除而不进行孤立删除?
我目前正在 ParentDao 中考虑这个问题:
public void removeChild(Parent parent, Child child)
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null;
try
session.beginTransaction();
session.delete(child);
session.getTransaction().commit();
parent.getChildren().remove(child);
session.refresh(parent);
catch (RuntimeException e)
if (tx != null)
tx.rollback();
throw e;
finally
session.close();
【问题讨论】:
【参考方案1】:当您打算手动执行 @Cascade(DELETE_ORPHAN)(来自 Hibernate)时,这里是执行几乎相同行为的代码。
实体:
class Library
@Id
private Integer id;
@OneToMany
private List<Book> books;
// getters and setters
class Book
@Id
private Integer id;
@ManyToOne
private Libraby library;
// getters and setters
还有一个简单的例子:
session.beginTransaction();
// load a library with ID = 1
Library library = session.get(Library.class, 1);
// assuming that your library has two books
Book book = library.getBooks().get(0); //gets the first book
library.getBooks().remove(0); // Remove this book from the library
session.delete(book);
session.getTransaction().commit();
您的 Book 将从数据库中删除,并且父级的 lisf 也将更新。
【讨论】:
实际上我的主要问题是:如果没有 DELETE_ORPHAN,我将如何手动完成? 我正在努力更好地理解它。 哦,好的,我将更改代码以使其更易于理解。一秒 好的,谢谢!但是如果我不刷新(图书馆),然后添加一本新书并再次直接调用 saveOrUpdate(图书馆),我得到一个 org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0];实际行数:0;预期:1 所以我想我需要先调用 refresh() 。从集合中移除已删除的对象是不够的。 哦,是的,如果你之后要添加另一个对象,那么你需要刷新它。此示例仅显示如何从集合和数据库中删除。事实上,我建议,在你运行这段代码之后,通过刷新它或再次使用这个库的 find 方法来重新加载你的对象;)【参考方案2】:你能试试下面的代码吗?在提交之前从列表中删除。
public void removeChild(Parent parent, Child child)
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null;
try
session.beginTransaction();
parent.getChildren().remove(child);
session.delete(child);
session.getTransaction().commit();
// session.refresh(parent); // this is not required
catch (RuntimeException e)
if (tx != null)
tx.rollback();
throw e;
finally
session.close();
【讨论】:
谢谢!但是如果我不刷新(父),然后添加一个新的子并再次直接调用 saveOrUpdate(parent),我得到一个 org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0];实际行数:0;预期:1 所以我想我需要先调用 refresh() 。从集合中移除已删除的对象是不够的。以上是关于Hibernate如何正确删除@OneToMany中的孩子?的主要内容,如果未能解决你的问题,请参考以下文章
Hibernate/H2 @OneToMany 删除子时“违反参照完整性约束”?
JPA 2 / Hibernate 孤儿删除仍然无法与@OneToMany 一起使用?
JPA 2.0 (Hibernate) 使用 @JoinTable 为 @OneToMany 生成不正确的连接表 PK
Hibernate @OneToMany 在更新父级时从列表中删除子级
删除元素时使用 JoinTable 和 OrderColumn 的 Hibernate 单向 OneToMany 映射中的约束冲突