Grails 2.5:domainObj.validate() 方法 returns false 当 domainObj.properties=params

Grails 2.5:domainObj.validate() method returns false when domainObj.properties=params

我正在尝试将我的 grails 应用程序从版本 1.3 升级到 2.5。我有一个域 class,其中一个字段是枚举。在控制器中,当我执行 domainObj.validate() 时,它总是 returns 错误。验证错误是 -

grails.validation.ValidationErrors: 1 个错误 字段 'typeEnum' 上的对象 'Parameter' 中的字段错误:拒绝值 [0];代码 [com.TypeEnum.typeMismatch.error,com.TypeEnum.typeMismatch,com.TypeEnum.typeMismatch.error,com.TypeEnum.typeMismatch,typeMismatch.com.TypeEnum,typeMismatch.pspValueTypeEnum,typeMismatch.com.TypeEnum,typeMismatch];参数 [typeEnum];默认消息 [无枚举常量 com.TypeEnum.0]

编辑进一步分析,我发现问题不在于枚举,而是在执行 parameterObj.properties = params 时,parameterObj.validate() returns 错误。

在我使用 Grails 2.5 的代码中,

parameterObj.validate()   //returns true

parameterObj.properties = params
// code to convert String from params to Enum object and assign it to parameterObj
parameterObj.enumField = MyEnumClass.getEnumByName(params.enumNameValue)
parameterObj.validate()   //This always return false

注:以上两种情况的validate(),parameterObj的字段值完全相同

在 Grails 2.5 中使用域 class 上的属性有什么变化吗?

如果您更改您的视图,以便他们将枚举的 name() 作为参数值发送,那么数据绑定就可以开箱即用。

至少我一直都是这样使用枚举的。

带名称的枚举数据绑定()

<g:select name="typeEnum" from="${TypeEnum.values()}" value="${obj.typeEnum}"/>

grails 然后使用每个枚举值的 .name() 作为值,使用 .toString() 作为显示的文本。这将生成如下内容:

<select name="typeEnum">
  <option value="STRING">String</option>
  <option value="NUMBER">Number</option>
  ...
</select>

控制器中的数据绑定可以很好地与域或命令对象一起工作:

def save1(PsparameterCmd cmd) {
  ...
  instance.properties = cmd.properties
}
def save2() {
  ...
  instance.properties = params
}

自定义枚举数据绑定

或者,您可以使用自定义数据绑定将 ID 转换为枚举值。

有不同的方法(文档:http://docs.grails.org/2.5.0/guide/theWebLayer.html#dataBinding): * 您可以为该类型注册一个全局数据绑定器(如果您在应用程序中大量使用该枚举) * 您可以在该单个字段上指定 dataBinding 注释(用于单次使用)

class Psparameter implements java.io.Serializable {
  @BindUsing({ obj, params ->
    return TypeEnum.values().find({ it.id == params.int('typeId') })
  })
  TypeEnum typeEnum
  ...
}

或全局转换器:

import org.grails.databinding.converters.ValueConverter
class TypeEnumConverter implements ValueConverter {
  boolean canConvert(value) {
    value instanceof Integer
  }
  def convert(value) {
    return TypeEnum.values().find({ it.id == value })
  }
  Class<?> getTargetType() {
    TypeEnum
  }
}

您必须在 resources.groovy

中注册
beans = {
  typeEnumConverter(your.package.TypeEnumConverter)
}

注意:据我所知(并且刚刚测试过),没有像TypeEnum.getTypeEnumById(value)这样的通用方法。这就是为什么我在上面的示例中使用 TypeEnum.values() 上的查找。

经过一段时间的努力,我终于在 Grails 2.5 中找到了针对此行为的解决方案。这是我的解决方案和观察结果。再次粘贴我的问题代码以供参考:

parameterObj.validate()   //returns true

 parameterObj.properties = params
// code to convert String from params to Enum object and assign it to parameterObj
parameterObj.enumField = MyEnumClass.getEnumByName(params.enumNameValue)
parameterObj.validate()   //This always return false
  1. 如果字段(如我示例中的 enumField)是枚举,则枚举字符串值应传递给域对象 (parameterObj) 而不是枚举对象。 例如,如果我的枚举是

     enum TypeEnum {
        STRING(0, "String"), NUMBER(1, "Number"), TIME(2, "Time")
         ...
       }
    

然后要发送到 domainObj 的值是 "STRING" 或 "NUMBER",等等

  1. 在我的例子中,如果我在将参数分配给属性后用 "STRING" 更新 enumField,那么验证仍然是 returns false。例如,

     parameterObj.properties = params
     parameterObj.enumField = "STRING"
     parameterObj.validate()  // returns FALSE
    

    所以我必须在执行 parameterObj.properties = params 之前更新 params 中的 enumField 以通过 validate() 方法获得正确的结果。因此,此序列中的以下代码可以正常工作。

     params.enumField = "STRING"
     parameterObj.properties = params
     parameterObj.validate()  // returns True as expected
    

    早期版本的 Grails 不是这种情况,我的应用程序在 Grails 1.3.3 版本上运行多年