Saturday, February 11, 2017

Persisting DateTime with zone information

Persisting DateTime with zone information


I was stuck a while ago trying to figure out how to map PersistentDateTimeTZ in a GORM class. Its an implementation of Hibernates UserType interface that persists a Joda DateTime value using 2 columns - one for the actual timestamp and one for the time zone. The DateTime class contains time zone information but a SQL timestamp column is time zone agnostic so you can lose data when the value is saved (the same exact problem exists when persisting java.util.Date values).

I could never figure out how to map the user type to my domain class property correctly. Just doing:

static mapping = {
dateTimeProperty type: PersistentDateTimeTZ
}

Failed with:

org.hibernate.MappingException: property mapping has wrong number of columns.

I seem to remember someone on the Grails mailing list suggesting I tried treating the value as an embedded type. That also didnt work as GORM embedded types have to be Groovy classes in grails-app/domain and PersistentDateTimeTZ is written in Java and lives in a library jar.

I finally found the solution in the 2nd Edition of The Definitive Guide to Grails (which I cant recommend enough, by the way). The trick is to pass a closure specifying the two columns to the property definition in the mapping builder. The working code looks like this:

static mapping = {
dateTimeProperty type: PersistentDateTimeTZ, {
column name: "date_time_property_timestamp"
column name: "date_time_property_zone"
}
}

The order of the columns corresponds to the order of the values returned by the sqlTypes() method of whatever UserType implementation youre using.


Available link for download