我有一个自定义验证器,如 -
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;
}
...
所以基本上,我需要根据某些条件进行一些验证,在我的验证中我需要执行查询。
但是,如果我这样做 -
def admin = new UserAccount(firstname:'Admin',email:'admin@example.com')
admin.save(flush:true)
admin.addToAuthorities("ADMIN").save(flush:true)
失败了。
Grails正在运行验证,即使在更新时也是如此,因为电子邮件存在验证失败。如果我这样做有什么不同
email {unique:true}
Grails说我不能写一个检查唯一性的自定义验证器。
答案 0 :(得分: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);
}
}
有关如何完成此操作的示例,请参阅UniqueConstraint。
答案 1 :(得分: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
}
可能需要进行一些修改,但上面的代码为您提供了一个示例
答案 2 :(得分:0)
感谢。我可以让它工作.admin.save()在插入和更新时调用验证。我处理了两个案例(插入和更新)并且能够使这个工作。
由于