Search code examples
grailsgroovygrails-ormone-to-many

How to prevent from Grails not to delete child while deleting parent?


i have one to many relationship between author and books, one author has many books..

i have domain class like this

Author.groovy

class Author {

    String authorName;
    String authorAddress;
    String authorCNIC;

    static hasMany = [books:Book]

    static constraints = {

        books(nullable: true)
    }
}

Book.groovy

class Book {

    String bookName;
    String Isbn;

    static belongsTo = [author:Author]

    static constraints = {

        author(nullable: true)
    }



}

now when i call this function

def deleteauthor()
    {
        def id=params.id
        Author author = Author.findById(id);
        author.delete(flush: true)
        render "Author Deleted"
    }

it deletes author and all of its child books..i do not want this behaviour, i want that it cannot delete author and books and display message cannot delete author, first delete books...please tell me how to do this ?


Solution

  • In your Author model you should add cascade: 'none' to constraints:

    class Author {
    
        String authorName;
        String authorAddress;
        String authorCNIC;
    
        static hasMany = [books:Book]
    
        static mapping = {
            cascade: 'none'
        }
    }
    

    This would prevent deleting books and would just set author_id to null.

    UPDATE:

    It seems that setting cascade 'none' would also disable cascading saves. So one option is to manually call save on every added book instance.

    Other thing I figured:

    You can set cascade to only work on save-update but then when Author is delete there is constraint violation exception, because there is not way to set on delete set null on Hibernate. We could do it manually on beforeDelete.

    class Author {
    
        String name;
    
        static hasMany = [books:Book]
    
        static mapping =  {
            books  cascade: 'save-update'
        }
    
        def beforeDelete() {
            Book.withNewSession {
                Book.findAllByAuthor(this).each {
                  it.author = null
                  it.save(flush: true)
                }
            }
       }
    }
    

    It seems to be working, although it's not very pretty.