【问题标题】:Grails 2.3.2: findOrCreate using Enums in BootstrapGrails 2.3.2:在 Bootstrap 中使用枚举 findOrCreate
【发布时间】:2013-11-17 13:30:58
【问题描述】:

我在使用 Bootstrap.groovy 中的 findOrCreateBy 方法时遇到问题。

class Guest {

    String firstname
    String lastname
    Gender gender

    static constraints = {
        firstname blank: false
        lastname blank: false        
        gender nullable: false
    }
}

enum Gender {
    MALE('male'), FEMALE('female')

    final String v

    Gender(String s) { v = s }
}

并且在 Bootstrap 中,如果访客还不存在,我会尝试创建它们。

Guest guest = Guest.findOrCreateByFirstnameAndLastnameAndGender(firstname, lastname, Gender.MALE)
guest.save()

我第一次针对 MySQL 运行应用程序时一切正常。应用程序启动时没有任何错误。如果我第二次运行该应用程序(这次是数据库中的访客),我会遇到以下失败。

| Error 2013-11-17 14:27:37,621 [localhost-startStop-1] ERROR context.GrailsContextLoader  - Error initializing the application: Unknown name value [1] for enum class [ch.silviowangler.ch.cisposiamo.Gender]
Message: Unknown name value [1] for enum class [ch.silviowangler.ch.cisposiamo.Gender]
    Line | Method
->>  105 | methodMissing                    in org.grails.datastore.gorm.GormStaticApi
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|    106 | createGuest                      in BootStrap
|    102 | createGuest . . . . . . . . . .  in     ''
|     66 | doCall                           in BootStrap$_closure1
|    308 | evaluateEnvironmentSpecificBlock in grails.util.Environment
|    301 | executeForEnvironment            in     ''
|    277 | executeForCurrentEnvironment . . in     ''
|    262 | run                              in java.util.concurrent.FutureTask
|   1145 | runWorker . . . . . . . . . . .  in java.util.concurrent.ThreadPoolExecutor
|    615 | run                              in     java.util.concurrent.ThreadPoolExecutor$Worker
^    744 | run . . . . . . . . . . . . . .  in java.lang.Thread

这似乎是 Gorm 第一次将值 '0' 和 '1' 写入数据库。在第二次运行中,它无法将这些 0 和 1 转换为相应的枚举值。谁能告诉我我做错了什么?

【问题讨论】:

  • 我创建了这个场景,但是,我无法重新创建错误。您确定错误不是来自其他操作吗?

标签: mysql grails enums grails-orm


【解决方案1】:

试试这个 - 将参数 generateSimpleParameterMetadata=true 添加到您的 url 连接字符串中,

...
url = "jdbc:mysql://localhost/bootstraptest?generateSimpleParameterMetadata=true"
...

这与驱动程序解释枚举元数据的方式有关(坦率地说我不太理解)见http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-configuration-properties.html

此解决方案非常特定于数据库,因此您不需要任何其他更改

请注意,实际的枚举标签现在将存储在数据库中('NEW'、'WIP'、'DONE' 而不是 0、1、2)

【讨论】:

  • 好点。它似乎是非常特定于数据库的。我明天会测试它,并会回复你
  • 优秀的答案。我一直在寻找这样的解决方案。谢谢。你帮了大忙!
【解决方案2】:

我认为这与mysql有关,我没有mysql来测试它并且从未使用过mysql,但尝试专门映射枚举,如下所示:

static mapping = {
    ...
    gender column: 'gender', sqlType: 'enum', name: 'gender'
}

ref

如果您手动创建数据库表,请尝试为您的列创建枚举,类似于:

CREATE TABLE sizes (
    name ENUM('small', 'medium', 'large')
);

ref

这是另一篇可以帮助here的文章

【讨论】:

  • 感谢您的快速回复。我需要保持数据库独立以便在例如运行测试。 H2 或将来使用不同的 DBMS 部署。因此,使用数据库特定的数据类型不是一种选择。还有另一种解决方法吗?对我来说,这件事就像一个错误。而且我很确定我可以使用 H2 文件数据库重现它。
  • 是的,这里也一样。嗯。会不会是 Hibernate 方言的问题?
【解决方案3】:

我建议使用IdentityEnumType更改映射:

static mapping = {
    ...
    gender column: 'gender', type: IdentityEnumType
}

通过添加 id 来修改您的枚举:

public enum Gender {

MALE   (1, "male"),
FEMALE (2, "female"),

final Integer id
final String value

Gender (Integer id, String value) {
    this.id = id
    this.value = value
}

String getValue() {
    return value
}

String toString() {
    return name()
}

String getKey() {
    return name()
}

这应该对你有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多