任务是支持在创建时最初输入的数据库中存储的用户名,并使用'ilike'标准代替'eq'检查唯一性。
在挖掘中,我看到了UniqueConstraint
的两个实现,一个由grails-datastore-gorm提供,另一个由grails-hibernate提供。我知道我需要在一个块中执行此查找,我在会话对象上重置FlushMode
,因此在验证数据之前,hibernate不会将更改保留到db。这是我写的自定义验证器:
@Override
protected void processValidate(final Object target, final Object propertyValue, Errors errors) {
def reject = false
doWithManualSessionIfAppropriate {
def targetId = null
try {
targetId = InvokerHelper.invokeMethod(target, 'ident', null)
} catch (Exception e) {
throw new GrailsRuntimeException('Could not determine id of target')
}
def results = []
results += constraintOwningClass."findAllBy${GrailsNameUtils.getClassName(constraintPropertyName, '')}Ilike"(propertyValue)
reject = results.any {
try {
def existingId = InvokerHelper.invokeMethod(it, 'ident', null)
targetId != existingId
} catch (Exception e) {
// the existing field is not in the db
false
}
}
}
if (reject) {
errors.rejectValue(constraintPropertyName, 'unique')
}
}
这使我们的集成测试通过,但是当我在调用importFrom
的控制器中使用它来验证用户名时,invokeMethod
无法在命令对象上找到id。例如:
RealUser.groovy:
class RealUser {
String username, passwordHash
static constraints = {
username iunique: true // where iunique is the name of my registered constraint
}
}
UserController.groovy:
@Validateable
class UserCommandObject {
String username, password, passwordConfirmation
static constraints = {
importFrom RealUser
}
}
当我unique: true
RealUser
时,UserCommandObject
验证就好了。当我将其更改为自定义验证程序iunique: true
时,UserCommandObject
会抱怨它不是域类。
我无法看到unique: true
如何对命令对象起作用,因为我看到的两个实现都只适用于域对象(并且在没有域对象的情况下调用时抛出GrailsRuntimeException
。)
有什么想法吗?我是否想过这个?
从另一个角度来看,是否有任何令人信服的理由不支持存入用户名,并且在验证之前只在输入上调用lower()
?
答案 0 :(得分:1)
自定义验证器中的findByPropertyNameIlike(val)会不会这样做?
static constraints = {
propertyName blank: false, validator: { val, obj, errors ->
def results = this.findByPropertyNameIlike(val)
if(results) {
errors.rejectValue('propertyName', 'unique.propertyName')
return false
}
return true
}
}