0

I am having troubles with using the findOrCreateBy method in the Bootstrap.groovy.

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

And in the Bootstrap I try to create Guests if they do not exist yet.

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

The first time I run the app against MySQL everything works fine. The apps starts without any error. If I run the app a second time (this time with guest in the database) I get the following failure.

| 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

It seems the the first time Gorm writes values '0' and '1' to the database. In the second run it fails to convert these 0 and 1 into the corresponding enum value. Can anybody tell me what I am doing wrong?

saw303
  • 8,051
  • 7
  • 50
  • 90
  • I created this scenario, however, I could not re-create the error. Are you sure the error is not from some other operation? – Alidad Nov 17 '13 at 15:05

3 Answers3

1

Try this - Add the parameter generateSimpleParameterMetadata=true to your url connect string,

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

This has something to do with the way the driver interprets the enum meta data (frankly i don't understand it well) see http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-configuration-properties.html

This solution is very db specific, so you don't need any other changes

Note that the actual enum label will now be stored in the database ('NEW', 'WIP', 'DONE' instead of 0, 1, 2)

aldrin
  • 4,482
  • 1
  • 33
  • 50
0

I think this is related to mysql, I dont have mysql to test it against and never worked with mysql, but try to specifically map the enum, like this:

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

ref

And if you are manually creating your database table , try to create the enum for your columns similar to this:

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

ref

This is another article that can help here

Community
  • 1
  • 1
Alidad
  • 5,463
  • 1
  • 24
  • 47
  • Thank you for your quick response. I need to stay database independent in order to run test on e.g. H2 or deploy the in future using a different DBMS. Therefore using a database specific datatypes is not an option. Is there another way to workaround it? To me this thing feels like a bug. And I am pretty sure I can reproduce it using an H2 file database. – saw303 Nov 19 '13 at 05:09
  • Yes, same over here. Mhm. Could it be an issue with the Hibernate dialect? – saw303 Nov 19 '13 at 06:03
0

I suggest to change mapping using IdentityEnumType:

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

Modify your Enum, by adding id to it:

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

That should help you.

rxn1d
  • 1,236
  • 6
  • 18