2014-03-03 34 views
0

任務是支持用戶名被存儲在數據庫中,因爲它們最初是在創建時鍵入的,並且使用'ilike'準則檢查唯一性'eq'。編寫一個必須在命令對象和域對象上工作的自定義grails唯一約束

在挖掘中,我看到了2個實現UniqueConstraint,其中一個由grails-datastore-gorm提供,另一個由grails-hibernate提供。我知道我需要在一個塊中執行這個查找,因爲我在會話對象上重置了FlushMode,所以hibernate在數據驗證之前不會將更改保存到數據庫。這是我寫的自定義的驗證:

@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 
    } 
} 

當我對RealUserunique: true,驗證就好了UserCommandObject。當我將其更改爲我的自定義驗證程序iunique: true時,UserCommandObject抱怨說它不是域類。

我不可能看到unique: true如何用於命令對象,因爲我看到的兩個實現只能在域對象上工作(並且在沒有域對象時調用GrailsRuntimeException)。

任何想法?我在想這個太過分了嗎?

從另一個角度接近,沒有任何令人信服的理由支持存儲用戶名作爲輸入的,只是呼籲輸入驗證lower()之前?

回答

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 
    } 
} 
相關問題