删除一对多关系中的子级会抛出 ObjectDeletedException
我只是不明白为什么 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可能会忽略的是,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 itsemployees
set and are now trying to delete one of those employees, Hibernate is telling you (by throwingObjectDeletedException
) that it will re-save deleted employee when it will saveOrganization
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 onOrganization
side, so changes (save / update) are propagated down toEmployee
level. As long as particularEmployee
instance is a member ofemployees
collection of anyOrganization
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 inEmployee
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 deleteEmployee
without removing it fromOrganization.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.