Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delete child in one-to-many relation throws ObjectDeletedException

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.

like image 468
slomir Avatar asked May 12 '11 00:05

slomir


1 Answers

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.

like image 78
ChssPly76 Avatar answered Nov 18 '22 19:11

ChssPly76