grails deleted object would be re-saved by cascade error
Asked Answered
D

4

9

I have the project as set-up below. I am trying to delete a project, and I get the following:

2010-09-29 11:45:22,902 [http-8080-1] ERROR errors.GrailsExceptionResolver  - deleted object would be re-saved by cascade (remove deleted object from associatio
ns): [Project#204]
org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [Project#204]
        at ProjectController$_closure6.doCall(ProjectController:50)
        at ProjectController$_closure6.doCall(ProjectController)
        at org.jsecurity.web.servlet.JSecurityFilter.doFilterInternal(JSecurityFilter.java:382)
        at org.jsecurity.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:180)
        at java.lang.Thread.run(Thread.java:619)

Is there any way to get hibernate to tell me which object has the reference back to the Project object that would be re-saved. What is wrong with my project set up that is causing this circular exception?

public class Project implements Comparable
{  
    static belongsTo = [employee:Employee]

    static hasMany = [roles:Role]
    static constraints = {

    }
    static mapping = {
          description type:"text"
          roles lazy:false, cascade:"all,delete-orphan"
          client lazy:false, cascade:"all,delete-orphan"
          employer lazy:false, cascade:"all,delete-orphan"
    }
}


class Employee implements Comparable
{
    static hasMany = [employeeDesiredSkills:EmployeeDesiredSkill,
                      employeeDesiredTools:EmployeeDesiredTool,
                      employeeAreasOfExpertise:EmployeeAreaOfExpertise,
                      projects:Project,
                      education:Education]


    static mapping = {
           employeeDesiredSkills cascade:"all,delete-orphan", lazy:false
           employeeDesiredTools cascade:"all,delete-orphan", lazy:false
           education cascade:"all,delete-orphan", lazy:false
           projects cascade:"all,delete-orphan", lazy:false
    }
}

public class Role implements Comparable
{

    static belongsTo = [project:Project]
    static hasMany = [roleSkills:RoleSkill,roleTools:RoleTool]

    static mapping = {
        duties type:"text"
        roleSkills cascade:"all,delete-orphan", lazy:false
        roleTools cascade:"all,delete-orphan", lazy:false
        locationType cascade:"all,delete-orphan", lazy:false

    }

    static contraints = {
        endDate(nullable: true)
        roleSkills(nullable: true)
        roleTools(nullable: true)
    }
}

class Employer implements Comparable
{
   static mapping = {
       type lazy:false, cascade:"all,delete-orphan"
   }
}

class RoleTool implements Comparable    
{


  static belongsTo = [role:Role, tool:Tool]//not sure this makes sense, but have to leave it or DB breaks
  Tool tool = new Tool(name:"")
    static mapping = {
      tool cascade:"save-update", lazy:false

    }


class RoleSkill implements Comparable   
{

  static belongsTo = [role:Role, skill:Skill]//not sure this makes sense, but have to leave it or DB breaks
    Skill skill = new Skill(name:"")
    static mapping = {
       skill cascade:"save-update", lazy:false

    }
}

class Skill implements Comparable
{
    static hasMany = [roleSkills:RoleSkill, employeeDesiredSkills:EmployeeDesiredSkill]

    static mapping = {
        roleSkills cascade:"all,delete-orphan", lazy:false
        employeeDesiredSkills cascade:"all,delete-orphan", lazy:false

    }

}

class Tool implements Comparable
{

    static hasMany = [roleTools:RoleTool, employeeDesiredTools:EmployeeDesiredTool]

    static mapping = {
        roleTools cascade:"all,delete-orphan", lazy:false
        employeeDesiredTools cascade:"all,delete-orphan", lazy:false

    }
}
Dirac answered 29/9, 2010 at 20:50 Comment(0)
Y
10

Infact, the way you have done the mapping projects cascade:"all,delete-orphan" in the Employee class.

You'll just need to do:

def employee = project.employee; 
employee.removeFromProjects(project);

And the project will be deleted as well. For more details, refer to GORM Gotchas By Peter Ledbrook. Its a 3 part series and explains many similar situations

Yeanling answered 1/10, 2010 at 11:54 Comment(1)
I finally got it working. It is not infact that simple. I think that there is a grails bug if the projects are stored in SortedSet, then it has a hard time doing that remove. I had to make a copy of the the projects, remove the one I wanted to delete, then add them back to employee to get this to workDirac
H
6

I know it is late but someone may like to find this here: What happens is that Hibernate uses 'dirtyChecking', as explained in GORM Gotchas By Peter Ledbrook.

To make things short: Hibernate, and so Grails will want to save() the employee object at the end of the Hibernate session (in your case at the .delete(flush:true) call) because it detects that the object has been modified (a project has been suppressed). And the employee must have kept a link toward the project, causing Hibernate to feel you will delete() the project to save() it back again.

To workaround this:

 def employee = project.employee; 
 employee.discard(); 
 project.delete(flush:true);

This tell Hibernate not to save() the employeewithout you asking for it.

Honor answered 4/10, 2011 at 13:26 Comment(0)
B
0

if you have cascade for delete setup, like you do, you need to remove the object-to-delete from its parent before deleting it. From your stacktrace in ProcectController around line 50.

Bet answered 29/9, 2010 at 20:59 Comment(2)
when you say "object to delete from its parent" does that mean that for this examle I need to remove Project from employee, or do I explicitly have to go down the tree removing all objects taht are about to be deleted from their parents?Dirac
Here is how I was doing the remove from ProjectController: def employee = project.employee; employee.removeFromProjects(project); project.delete(flush:true)Dirac
A
0

It because at the end of transaction, grails and hibernate will be auto save Parent object, and it detected that a Child deleted so it will not allow delete the Object. So we need:

child.parent.discard()
child.delete()

You can refer here. It resolve my issue.

Absolute answered 26/5, 2023 at 10:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.