Grails自定义验证 - 查询内部验证检查 - 更新时会发生什么?

Roc*_*kyJ 5 grails

我有一个自定义验证器,如 -

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;
      }
Run Code Online (Sandbox Code Playgroud)

...

基本上,我需要根据某些条件进行一些验证,在我的验证中我需要执行查询.

但是,如果我这样做 -

def admin = new UserAccount(firstname:'Admin',email:'admin@example.com')


admin.save(flush:true)


admin.addToAuthorities("ADMIN").save(flush:true)
Run Code Online (Sandbox Code Playgroud)

它失败.

Grails正在运行验证,即使在更新时也是如此,因为电子邮件存在验证失败.如果我这样做,那会有什么不同

email {unique:true}

Grails说我不能写一个检查唯一性的自定义验证器.

Gre*_*ant 6

不确定这是否是你的问题,但当我尝试创建这样的验证(即对数据库进行查询的那个)时,我会得到一个StackOverflowError.原因是,当您运行查询(如findByEmail)时,Hibernate将尝试刷新会话,这将导致它验证所有瞬态对象,然后再次调用您的自定义验证器,从而导致无限递归.

防止这种情况的诀窍是在运行查询时将会话的刷新模式设置为"手动"一小段时间.这可以防止Hibernate在运行查询之前尝试刷新会话.副作用是您的查询不会返回您在当前会话中创建但尚未保留(刷新)回到数据库的实体.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

有关如何完成此操作的示例,请参阅UniqueConstraint.


Kri*_*ols 0

另一种方法可能是在 save 方法中进行检查。

def save = {
  ..
  if (some_checks_succeed(userEmail, userAccount)) {
    admin.save(flush: true)
  }
  ..
}

def some_checks_succeed = { String userEmail, String userAccount ->
  boolean valid = true;
  if (userAccount.authenticationChannel == "ABC") {
    UserAccount.withNewSession {
    if (UserAccount.findByEmail(userEmail)) {
     valid = false;
    } else if (UserAccount.findByName(userEmail)) {
     valid = false;
    }

    ..
  }

  return valid
}
Run Code Online (Sandbox Code Playgroud)

可能需要进行一些修改,但上面的代码为您提供了一个示例