k s
k s

Reputation: 882

Grails hasMany enum with a custom hibernate UserType

I have an enum with a hibernate custom UserType:

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

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

The ProgramUserType stores the code (1000, 1001, etc) for the enum and gets the enum instance back via the code when read from the database.

This is in use successfully on a relationship in a domain class:

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

So, all of the above works fine.

But I want to use the enum in a hasMany relationship:

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

My issue is that always produces a column with a "varchar2(255 char)" type:

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

I've tried various things to no avail:

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: [...]

etc.

What is the proper syntax to use a custom user type in a join table mapping?

(I'm using grails 2.3.7)

Upvotes: 2

Views: 796

Answers (2)

hakuna1811
hakuna1811

Reputation: 534

I don't know why you do this complex but in order to write a code(Integer, Long, String...) into a column of database from an enum, you can implement simply like this:

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() }
}

The importance line of code is Integer getId() { id } You can change id property to whatever type you want. Hope it help

some reference links GRAILS-3633 or in another discussion

Upvotes: 3

dmahapatro
dmahapatro

Reputation: 50245

type cannot be specified for the inverse column in joinTable. It looks like one should be able to mention any other column config from this line but it does not work. You can raise a JIRA issue as enhancement/bug/feature request and/or drop the idea of using joinTable but create an actual domain class to handle the XRef table. For example, in lines of something like:

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

with

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

and

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

There will be a little bit of boiler plate code involved like implementing equals() and hasCode() in DomainProgram but will create the columns as desired.

Upvotes: 1

Related Questions