【问题标题】:Delete child in one-to-many relation throws ObjectDeletedException删除一对多关系中的子项抛出 ObjectDeletedException
【发布时间】:2011-05-12 00:08:23
【问题描述】:

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

我有以下情况:

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

组织.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

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

休眠抛出...

 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 中到 Employee(s) 的关系映射中删除 cascade="save-update" 时,一切正常
2. 当我从删除方法中删除 @Transactional 注释时,一切正常。
3. 当我从孩子的父母(组织)列表中删除孩子(员工)时,然后执行删除,一切正常。

问题

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

【问题讨论】:

    标签: hibernate one-to-many


    【解决方案1】:

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

    考虑到您的情况,如果您已加载 Organization 及其 employees 集并且现在正试图删除其中一名员工,Hibernate 会告诉您(通过抛出 ObjectDeletedException)它将重新保存已删除的员工何时保存Organization,因为您已声明保存或更新应从组织级联到其集合中的员工。

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

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

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

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

    【讨论】:

    • 感谢您的回答。你是对的,它是这样工作的,但我之前没有加载任何组织对象。当 Hibernate 考虑对组织对象进行任何操作以级联任何东西时,我仍然不明白。起初我提供的信息不足,所以我用更多可能重要的信息编辑了我的问题。
    • 如果我的问题打扰到您,请见谅。我做了更多的实验,并澄清了一些事情。我只有一个困惑:当会话关闭/刷新时,组织是否会自动保存,而不管组织或她的员工列表上没有任何明确的操作?换句话说,组织实例何时更新/保存?
    • @slomir - 所有在会话中加载(由您直接或由 Hibernate 在后台加载)的实体在刷新会话时保留.但是,这并不意味着每个实体都会向数据库发出实际的 UPDATE 语句 - 仅保存实际更改。如果您没有直接加载您的组织,它是由 Hibernate 通过 Employee(或其他一些实体)上的关联加载的
    • 非常感谢您的回答。谢谢你,现在我明白了:)
    • 1 个问题...无关紧要不是一个词。你从字面上只是说不顾一切......:-|
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多