【问题标题】:Grails hasMany enum with a custom hibernate UserType带有自定义休眠用户类型的 Grails hasMany 枚举
【发布时间】:2014-08-05 21:06:50
【问题描述】:

我有一个带有休眠自定义用户类型的枚举:

enum Program { ABC(1000), XYZ(1001); final long code; ... }

class ProgramUserType implements org.hibernate.usertype.UserType { ... }  

ProgramUserType 存储枚举的代码(1000、1001 等),并在从数据库读取时通过代码获取枚举实例。

这已成功用于域类中的关系:

class MyDomainOne {
    Program program
    ...
    static mapping = {
        ...
        program column: 'PROGRAM_ID', type: ProgramUserType
        ...
    }
}

所以,上述所有工作都很好。

但我想在 hasMany 关系中使用枚举:

class MyDomainTwo {
    ...
    static hasMany = [
        programs: Program
    ]
    ...
    static mapping = {
        ...
        programs joinTable: [name: 'BLAH_DOM_TWO_PROGS', key: 'DOM_TWO_ID', column: 'PROGRAM_ID']
        ...
    }
}

我的问题是总是产生一个“varchar2(255 char)”类型的列:

BLAH_DOM_TWO_PROGS (DOM_TWO_ID number(19,0) not null, PROGRAM_ID varchar2(255 char));

我尝试了各种方法都无济于事:

programs joinTable: [name: 'BLAH_DOM_TWO_PROGS', key: 'DOM_TWO_ID', column: 'PROGRAM_ID', type: ProgramUserType]

programs joinTable: [name: 'BLAH_DOM_TWO_PROGS', key: 'DOM_TWO_ID', column: 'PROGRAM_ID', type: ProgramUserType, sqlType: 'NUMBER(10,0)']

programs type: ProgramUserType, joinTable: [...]

等等

在连接表映射中使用自定义用户类型的正确语法是什么?

(我使用的是 grails 2.3.7)

【问题讨论】:

    标签: hibernate grails grails-orm


    【解决方案1】:

    我不知道你为什么要这么复杂,但是为了将代码(整数、长整数、字符串...)从枚举写入数据库列,你可以像这样简单地实现:

    enum Program {
        ABC(0, "ABC"),
        XYZ(1, "XYZ"),
    
        final String value
        final Integer id
    
        Program(Integer value, String selectValue) {
            this.id = value
            this.value = selectValue
        }
    
        //https://github.com/tudor-malene/Easygrid/issues/22
        //shows value in select drop down
        String toString() { value }
    
        //stores value in database
        Integer getId() { id }
    
        //returns Enum constant associated with value
        String getKey(){ name() }
    }
    

    重要的代码行是Integer getId() { id } 您可以将 id 属性更改为您想要的任何类型。 希望对你有帮助

    一些参考链接GRAILS-3633in another discussion

    【讨论】:

    • 我正在尝试这个,如果我的测试通过,这将是我选择的答案。在枚举中添加“long getId()”会导致生成的 ddl 为 number(19,0) 类型。我很好奇您是否可以指出任何 grails 文档显示将 getId() 方法添加到枚举会产生这种魔力(即不需要自定义 UserType)......从数据库读取时它如何解析 id ?
    • 这是我最初的想法,以确保枚举本身提供与toString() 的实现类似的值,当关联使用时,但我不知道getId() 是否可以解决问题。也很想知道。
    • 我不知道我是如何错过多年来可以将 getId 添加到 grails 中的枚举的。谢谢你。我再也不会写自定义 UserType 了。这有助于生成我试图完成的正确连接表定义。
    • 当我想找到一个解决方案将枚举作为整数存储在数据库中但仍然在选择标签中显示一些字符串时,我想到了这非常方便。我将更新一些指向我的答案的链接。
    • grails.org/1.1+Release+Notes 1.1?!现在我觉得更蠢了 :) 但我还没有在 grails 文档中找到它。
    【解决方案2】:

    type 不能为 joinTable 中的反列指定。看起来应该可以从this line 中提及任何其他列配置,但它不起作用。您可以提出 JIRA 问题作为增强/错误/功能请求和/或放弃使用 joinTable 的想法,但创建一个实际的域类来处理外部参照表。例如,在这样的行中:

    class DomainProgram implements Serializable {
    
        MyDomainTwo myDomain
        Long programId
    
        static mapping = {
            id composite: ['myDomain', 'programId']
            table 'DOMAIN_PROGRAM'
            myDomain column: 'DOMAIN_ID'
            programId column: 'PROGRAM_ID'
        }
    }
    

    class MyDomainTwo {
        def getPrograms() {
            DomainProgram.findByMyDomain(this)*.programId.collect { 
                Program.getEnum it 
            }
        }
    }
    

    enum Program {
        ABC(1000), XYZ(1001)
    
        final long code
    
        private Program(long _code) {
            code = _code
        }
    
        long getValue() {
            code
        }
    
        static Program getEnum(long value) {
            values().find { it.code == value }
        }
    }
    

    将涉及一些样板代码,例如在 DomainProgram 中实现 equals()hasCode(),但会根据需要创建列。

    【讨论】:

    • 鉴于link that you referenced 看起来您应该可以指定任何ColumnConfig attributes (不包括“类型”)...我自己返回了一个尝试过的 sqlType 甚至 enumType : 'ordinal' 但对生成的 ddl 没有任何影响。看到后我认为这是一个错误。
    猜你喜欢
    • 2012-01-16
    • 1970-01-01
    • 2023-03-03
    • 2014-04-11
    • 1970-01-01
    • 2011-09-11
    • 2022-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多