z00bs
z00bs

Reputation: 7498

Grails: Rollback associations done by data binding in a service

Given the following two domain classes:

class Book {
    String title

    static hasMany = [authors: Author]
    static belongsTo = Author
    static constraints = {
        title(nullable: false)
    }
}

class Author {
    static hasMany = [books: Books]
}

We create and persist domain objects in services and make use of the data binding feature of Grails. Such a method looks like the following one:

def createAndPersistBook(params) throws ValidationException {
    log.debug("Attempt to create and persist book")
    Book book = new Book(params)
    book.save(flush: true, failOnError: true)
    log.debug("Created: ${book}")
    book
}

When we pass the params map

params = ["authors": "[2]"]

to the service method (there is no title defined thus validation will fail) the association from the newly created book to the already existing author (and vice-versa) is done by data binding. But since the title is nullable: false and not defined a ValidationException is thrown and the transaction is rolled back.

What we expected now is that the book is not being saved, but Book.list().isEmpty() returns false. We think that this is because of the dirty-check by hibernate, meaning the books collection of the existing author has changed and will be persisted and this save gets cascaded to the book instance.

What is the best way to prevent grails from saving the book in this scenario? Or why is the association done by data binding not properly rolled back when validation fails?

Upvotes: 1

Views: 472

Answers (1)

Greg
Greg

Reputation: 116

If you've specified that your service is transactional, any uncaught exception will cause a transaction to rollback within a service method. The only thing that might stand in your way is if your RDBMS does not support true transactions/rollback.

Have you specified whether the service is transactional? You should have a statement such as below to declare the service is transactional.

def transactional = true

Upvotes: 0

Related Questions