In my previous blog we have seen how to set failOnError and flush globally. In this blog I am providing a use case of failOnError and flush.
Lets have a simple domain class
|
class Person { String firstName String lastName String email static constraints = { firstName nullable: false, blank: false lastName nullable: true email nullable: true, email: true, unique: true } } |
|
- failOnError: when it is set to true then save() method will throw ValidationException when validation fails during save.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
def failOnErrorTest() { log.info "Total person = ${Person.count()}" try { Person person = new Person(firstName: 'Manish', lastName: 'Bharti', email: 'invalid email') <strong>person.save()</strong> } catch (Exception e) { log.error "Inside catch: Without failOnError (Not Printed)" } finally { log.info "Inside finally: Without failOnError, Total person = ${Person.count()}" } try { Person person = new Person(firstName: 'Manish', lastName: 'Bharti', email: 'invalid email') <strong>person.save(failOnError: true)</strong> } catch (Exception e) { log.error "Inside catch: With failOnError" } finally { log.info "Inside finally: With failOnError, Total person = ${Person.count()}" } } |
|
In the above code snippet, I have given invalid email address in both the places but in second try..catch I have used failOnError while saving the Person instance. But in domain class we have declared email: true so application does not allow us to save the data. And should warn us for that. Lets see what we got in console
|
INFO test.PersonService - Total person = 1 INFO test.PersonService - Inside finally: Without failOnError, Total person = 1 ERROR test.PersonService - Inside catch: With failOnError INFO test.PersonService - Inside finally: With failOnError, Total person = 1 |
|
While first save (without failOnError: true) our catch block is not executed and person instance is not saved as well, person count is still 1. But in second save (with failOnError: true) catch block is executed and there we can warn user that data was not saved.
- flush: when it is set to true then save() method flush the session immediately and save data in the database.
|
def flushTest() { log.debug "Person Original Count = ${Person.count()}" Person person = new Person(firstName: 'Manish', lastName: 'Bharti', email: 'manish@example.com') person.save(failOnError: true) log.debug "Person count after first save = ${Person.count()}" <strong>person.delete()</strong> log.debug "Person count after delete = ${Person.count()}" Person person1 = new Person(firstName: 'Monu', lastName: 'Bharti', email: 'manish@example.com') person1.save(failOnError: true) log.debug "Person count after second save = ${Person.count()}" } |
|
In the above code snippet, at first I am creating a person with email address manish@example.com then deleting and creating another person with the same email address. If we run the code we got the following exception
|
Field error in object 'myApp.Person' on field 'email': rejected value [manish@example.com]; codes [myApp.Person.email.unique.error.test.Person.email, ...]; arguments [email,class myApp.Person, manish@example.com]; default message[Property [{0}] of class [{1}] with value [{2}] must be unique] |
|
This is because we are trying to create a new person with the same email address while another person still exists with the given email address.
To overcome this exception we need to use flush: true, like:
|
person.delete(flush: true) |
|
And our method execute correctly.
Console output:
|
DEBUG - Person Original Count = 0 DEBUG - Person count after first save = 1 DEBUG - Person count after delete = 0 DEBUG - Person count after second save = 1 |
|
Hope this helps. 🙂
Recent Comments