Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grails Custom Validation - Query inside validation check - What happens while updating?

Tags:

grails

I have a custom validator like -

validator: { userEmail, userAccount ->

   if (userAccount.authenticationChannel == "ABC") {
      boolean valid = true;
      UserAccount.withNewSession {
      if (UserAccount.findByEmail(userEmail)){
         valid = false;
      }
      else if (UserAccount.findByName(userEmail)) {
         valid = false;
      }

...

So basically, I need some validation based on some condition and in my validation I need to execute a query.

But, now if I do -

def admin = new UserAccount(firstname:'Admin',email:'[email protected]')


admin.save(flush:true)


admin.addToAuthorities("ADMIN").save(flush:true)

It fails.

Grails is running the validation, even on update and since email exists validation fails. How is this different if I do

email {unique:true}

Is Grails saying that I cannot write a custom validator which checks uniqueness.

like image 779
RockyJ Avatar asked Aug 10 '10 09:08

RockyJ


1 Answers

Not sure if this is your issue or not, but when I tried to create a validation like this (ie. one that does queries against the database), I would get a StackOverflowError. The reason is that, when you run a query (like findByEmail), Hibernate will try to flush the session, which will cause it to validate all transient objects, which in turn calls your custom validator again, resulting in infinite recursion.

The trick to prevent this is to set the flush mode of the session to "manual" for a short time while running the queries. This prevents Hibernate from trying to flush the session before running the queries. The side-effect is that your query won't return entities you created in the current session but haven't been persisted (flushed) back to the database yet.

UserAccount.withNewSession { session ->
    session.flushMode = FlushMode.MANUAL
    try {
        if (UserAccount.findByEmail(userEmail)){
            valid = false;
        }
        else if (UserAccount.findByName(userEmail)) {
            valid = false;
        }
    }
    finally {
        session.setFlushMode(FlushMode.AUTO);
    }
}

See UniqueConstraint for an example of how this is done.

like image 163
GreenGiant Avatar answered Sep 19 '22 21:09

GreenGiant