I'm using grails 2.3.4 and I have a domain class that embeds an object. The embedded object has a property called 'version' and it seems that this is conflicting with the 'version'-field automatically added to the database-table by GORM. The result is that the 'version'-field belonging to my embedded object isn't created in the database and as a consequence my application doesn't work properly.
My code looks like this:
class Thing {
String someText
EmbeddedThing embeddedThing
Date someDate
static embedded = ['embeddedThing']
static constraints = {
embeddedThing(unique: true)
}
}
class EmbeddedThing {
String textOfSomeSort
String version
String textOfSomeOtherSort
}
You might think that a quick fix is to rename the 'version'-property of the embedded object but the class belongs to an included sub-project (i.e. a JAR-file) that I'm not allowed to touch since other projects use it. So the solution needs to be done completely within my domain class, or at least in a manner that doesn't change the class of the embedded object.
I actually found a solution to this problem by using a Hibernate UserType to represent the EmbeddedThing-class. My code now looks like this and works perfectly:
Thing.groovy:
import EmbeddedThingUserType
class Thing {
String someText
EmbeddedThing embeddedThing
Date someDate
static embedded = ['embeddedThing']
static mapping = {
version false
embeddedThing type: EmbeddedThingUserType, {
column name: "embedded_thing_text"
column name: "embedded_thing_version"
column name: "embedded_thing_other_text"
}
}
static constraints = {
embeddedThing(unique: true)
}
}
EmbeddedThing.groovy:
class EmbeddedThing {
String textOfSomeSort
String version
String textOfSomeOtherSort
}
EmbeddedThingUserType.groovy:
class EmbeddedThingUserType implements UserType {
int[] sqlTypes() {
return [StringType.INSTANCE.sqlType(),
StringType.INSTANCE.sqlType(),
StringType.INSTANCE.sqlType()]
}
Class returnedClass() {
return EmbeddedThing
}
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
throws HibernateException, SQLException {
if (resultSet && names) {
return new EmbeddedThing(
textOfSomeSort: resultSet?.getString(names[0] ?: '_missing_textOfSomeSort_'),
version: resultSet?.getString(names[1] ?: '_missing_version_'),
textOfSomeOtherSort: resultSet?.getString(names[2] ?: '_missing_textOfSomeOtherSort_'))
} else {
return null
}
}
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index)
throws HibernateException, SQLException {
if (value != null) {
preparedStatement.setString(index, value?.textOfSomeSort)
preparedStatement.setString(index + 1, value?.version)
preparedStatement.setString(index + 2, value?.textOfSomeOtherSort)
} else {
preparedStatement.setString(index, '_missing_textOfSomeSort_')
preparedStatement.setString(index + 1, '_missing_version_')
preparedStatement.setString(index + 2, '_missing_textOfSomeOtherSort_')
}
}
@Override
public boolean isMutable() {
return false
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
return x.equals(y)
}
@Override
public int hashCode(Object x) throws HibernateException {
assert (x != null)
return x.hashCode()
}
@Override
public Object deepCopy(Object value) throws HibernateException {
return value
}
@Override
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return original
}
@Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value
}
@Override
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return cached
}
}
Config.groovy:
grails.gorm.default.mapping = {
'user-type'( type: EmbeddedThingUserType, class: EmbeddedThing)
}