删除一对多关系中的子级会抛出 ObjectDeletedException

发布于 2024-11-06 19:39:15 字数 1916 浏览 0 评论 0原文

我只是不明白为什么 Hibernate 会抛出标题中提到的异常。我可能不理解 Hibernate 背后的状态管理思想。

我有以下情况:

组织和员工之间的一对多关系

Organization.hmb.xml

<set name="employees" inverse="true" cascade="save-update">  
    <key column="organization_id"/>  
    <one-to-many class="Employee"/>  
</set>

Employee.hbm.xml

<many-to-one name="organization" class="Organization"  column="organization_id" />

我使用标准 Spring/Hibernate 应用程序架构以及服务和 DAO,其中 DAO 扩展了 HibernateDaoSupport 类并使用 HibernateTemplate 类的服务进行会话管理。

当我尝试在这种情况下删除员工时...

Employee e=employeeService.read(1); 

//EDIT: Important! delete operation in EmployeeService is (@)transactional  
employeeService.delete(e); //this call just delegate execution to employeeDao.delete

编辑:我一开始没有提到服务层中的删除操作是事务性的,这似乎是重要信息(继续阅读)!

Hibernate 抛出...

 ObjectDeletedException: deleted object would be re-saved by cascade...

EmployeeService 中的删除操作看起来像...

  @Transactional public void delete(Employee emp){  
    Employee e=employeeDao.read(emp.getId());  
    if(e==null)  
        throw NoSuchOrganizationException();  

    /*...several while-s to delete relations where Employee is  
    not owner of relation... */

    employeeDao.delete(e);  
}

场景(它们不相关):
1. 当我从 Organization.hbm.xml 中到员工的关系映射中删除cascade="save-update"时,一切正常
2.当我从删除方法中删除@Transactional注释时,一切正常。
3. 当我从父级(组织)子级列表中删除子级(员工),然后执行删除时,一切正常。

问题

为什么 Hibernate 关心父类中的级联
他在组织对象上考虑级联的执行点在哪里? 为什么他不能用 DELETE FROM... 删除 Employee(Child) ,就是这样。此外,员工是关系的所有者,对他执行的操作应该管理关系本身。 当他想在提到的场景中调用组织对象上的任何操作时?我就是不明白。

I just don't understand why Hibernate throws exception mentioned in title. I probably don't understand state management idea behind Hibernate.

I have following situation:

One-to-many relation between Organization and Employee

Organization.hmb.xml

<set name="employees" inverse="true" cascade="save-update">  
    <key column="organization_id"/>  
    <one-to-many class="Employee"/>  
</set>

Employee.hbm.xml

<many-to-one name="organization" class="Organization"  column="organization_id" />

I use standard Spring/Hibernate app architecture with Services and DAOs, where DAOs extend HibernateDaoSupport class and use services of HibernateTemplate class for Session management.

When I try to delete Employee in this scenario...

Employee e=employeeService.read(1); 

//EDIT: Important! delete operation in EmployeeService is (@)transactional  
employeeService.delete(e); //this call just delegate execution to employeeDao.delete

EDIT: I did not mention at first that delete operation in Service layer is transactional which seems to be important info (keep reading)!

Hibernate throws...

 ObjectDeletedException: deleted object would be re-saved by cascade...

Delete operation in EmployeeService looks like...

  @Transactional public void delete(Employee emp){  
    Employee e=employeeDao.read(emp.getId());  
    if(e==null)  
        throw NoSuchOrganizationException();  

    /*...several while-s to delete relations where Employee is  
    not owner of relation... */

    employeeDao.delete(e);  
}

Scenarios (they are not related):
1. When i remove cascade="save-update" from relation mapping to Employee(s) in Organization.hbm.xml, everything works fine.
2. When i remove @Transactional annotation from delete method everything works fine.
3. When i delete child(Employee) from parent(Organization) list of children, and then execute delete, everything works fine.

Question:

Why Hibernate cares at all about cascade in parent class?
Where is the point in execution at which he considers cascade on Organization object?
Why he just can't delete Employee(Child) with DELETE FROM... and that's it. Besides, Employee is the owner of relationship and operations executed on him should manage relation itself. When he thought to call any operation on Organization object in mentioned scenario anyway? I just don't get it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

剩余の解释 2024-11-13 19:39:15

您可能会忽略的是,Hibernate 会自动维护已加载并存在于 Session 中的实体的状态,这意味着无论您是否显式调用“update()”方法,它都将保留对它们所做的任何更改无论

考虑到您的场景,如果您已加载 Organization 及其 employees 集,并且现在尝试删除其中一名员工,Hibernate 会告诉您(通过抛出 ObjectDeletedException< /code>),当它保存组织时,它会重新保存已删除的员工,因为您已经声明保存或更新应该从组织级联到其集合中的员工。

处理此问题的正确方法是在删除该员工之前从组织的员工集中删除该员工,从而防止级联重新保存。

编辑(基于更新的问题):

组织 拥有员工集合。级联始终遵循关联 - 您已在 Organization 端声明它,因此更改(保存/更新)会向下传播到 Employee 级别。只要特定的Employee实例是会话中任何Organization实体的employees集合的成员,它就会被保存(或重新已保存,因此当会话刷新/关闭时会抛出异常。

关联是从 Employee 侧映射的(例如 organization_id 列驻留在 Employee 表中)这一事实在此无关紧要;它可以通过连接表进行映射,并得到相同的结果。 Hibernate 通过会话维护“状态”,当您尝试删除 Employee 而不将其从 Organization.employees 中删除时,您将向 Hibernate 发出冲突的指令(因为它仍然存在 -并且必须保存在一个地方,但在另一个地方被删除),因此是例外。

What you may be missing is that Hibernate automatically maintains state for entities that have been loaded and exist in Session, meaning it will persist any changes made to them irregardless of whether you explicitly invoke "update()" method.

Considering your scenario, if you have loaded Organization and its employees set and are now trying to delete one of those employees, Hibernate is telling you (by throwing ObjectDeletedException) that it will re-save deleted employee when it will save Organization because you've declared that saving or updating should be cascaded from organization down to employees in its set.

The proper way to handle this would be to remove said employee from organization's employees set before deleting it thus preventing cascaded re-save.

Edit (based on updated question):

Organization owns collection of employees. Cascade always follows the association - you've declared it on Organization side, so changes (save / update) are propagated down to Employee level. As long as particular Employee instance is a member of employees collection of any Organization entity that lives in session, it will be saved (or re-saved, so Exception is thrown) when session is flushed / closed.

The fact that association is mapped from Employee side (e.g. organization_id column resides in Employee table) is irrelevant here; it could have been mapped via join table with the same results. Hibernate maintains "state" via session and when you're trying to delete Employee without removing it from Organization.employees you're giving Hibernate conflicting instructions (since it's still alive - and has to be saved - in one place but is deleted in the other), hence the exception.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文