Search code examples
javajpaeclipselinkjpql

How to query properties of an @Entity attribute mapped using EclipseLink @ReadTransformer and @WriteTransformer?


I am using EclipseLink 2.4.2.

I have an @Entity with an attribute of type Money, which is a final class from an external library. Instances of Money are immutable and must be persisted as two columns, one for amount and one for currency.

I am using a @ReadTransformer and two @WriteTransformers to do this:

@Transformation(fetch = FetchType.EAGER, optional = false)
@ReadTransformer(transformerClass = MoneyReadTransformer.class)
@WriteTransformers({
        @WriteTransformer(
                transformerClass = MoneyCurrencyWriteTransformer.class,
                column = @Column(name = "SAVINGS_CURRENCY", nullable = false)),
        @WriteTransformer(
                transformerClass = MoneyAmountWriteTransformer.class,
                column = @Column(name = "SAVINGS_BALANCE", nullable = false))
})
private Money savings;

This works well; I can load and save the entity with no problem.

The problem comes when I try to perform a JPQL query for entities based on attributes of the embedded Money instance:

SELECT t FROM Thing t WHERE t.savings.amount > 0;

This returns:

org.eclipse.persistence.exceptions.JPQLException: 
Exception Description: Problem compiling [SELECT t FROM Thing t WHERE t.savings.amount > 0]. 
[29, 45] The state field path 't.savings.amount' cannot be resolved to a valid type.

This kind of thing worked in Hibernate just fine (with UserTypes and a @Type annotation).

I also noted the following messages on startup:

[EL Config]: metadata: 2013-04-28 15:30:04.276--Thread(Thread[main,5,main])--The default table generator could not locate or convert a java type (null) into a database type for database field (THING.SAVINGS_CURRENCY). The generator uses java.lang.String as default java type for the field.
[EL Config]: metadata: 2013-04-28 15:30:04.276--Thread(Thread[main,5,main])--The default table generator could not locate or convert a java type (null) into a database type for database field (THING.SAVINGS_BALANCE). The generator uses java.lang.String as default java type for the field.

These messages go away if I define a columnDefinition on the @Column attribute for each @WriteTransformer.

What might the problem be? My suspicion is that something's not right with the transformers, maybe I'm not setting a type hint somewhere - but it's non-obvious and examples are few and far between.


Solution

  • You should map Money as an Embeddable/Embedded relationship, not using a TransformationMapping. This would allow querying of it and be standard JPA. Not sure what your talking about with Hibernate, TransformationMapping is specific to EclipseLink, so most certainly will not work with Hibernate.

    To enable querying for TransformationMappings you can use a QueryKey. You would need to define a query key for the columns using a DescriptorCustomizer, and would then be able to query the columns in JPQL using whatever name you gave the query key. In EclipseLink you can also use the JPQL COLUMN() function to query any un-mapped database column directly.

    http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Query_Keys

    http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/j_column.htm#column