How to fetch contents of @ElementCollection table mapped via @MapKeyColumn

Viewed 385

There are many questions similar to this here but after a lot of looking, I have not found this question or an answer to it.

I have an entity with an @ElementCollection mapped like this:

@Entity
public class MyEntity {
    ...
    @ElementCollection(fetch = FetchType.EAGER)
    @MapKeyColumn(name = "value")
    @Column(name = "description")
    private Map<String, String> validValues = new HashMap<>();

    @Column
    protected Long otherId;

This configuration works fine, I did not specify a name for the mapped table but Hibernate created it automatically from the mapping and named it my_entity_valid_values. Fetching these values via Hibernate works fine for each MyEntity instance, the problem is with performance for large data sets.

In my app, I can have large collections of MyEntity objects and rather than rely on Hibernate's eager fetching which produces n queries I would like to fetch them all myself. I am trying this HQL:

select e.id,vv from MyEntity e join e.validValues vv where e.otherId=14

This results in the following SQL:

select
    myentity0_.id as col_0_0_,
    validvalue1_.description as col_1_0_ 
from
    my_entity myentity0_ 
inner join
    my_entity_valid_values validvalue1_ 
        on myentity0_.id=validvalue1_.my_entity_id 
where
    myentity0_.other_id=14

The my_entity_valid_values table as created by Hibernate has 3 columns, my_entity_id which is the foreign key back to the source table, and also value and description columns which are the two columns that represent the keys and values for the Map<String, String> mapping.

However, the SQL that is generated from the vv reference in the HQL only includes the description column, which omits the value column and provides an incomplete picture of this data. How can I get both the value and description columns in this case? I have tried HQL such as:

select e.id,vv.value,vv.description ...

But this gives me org.hibernate.QueryException: cannot dereference scalar collection element.

Any tips welcome!

1 Answers

Thanks to this answer in another question I figured this out, the answer is to reference the collection column with index() like this:

select e.id,index(vv),vv from MyEntity e join e.validValues vv where e.otherId=14

This adds the value column (in my case the column passed to @MapKeyColumn) and returns all of the data I need from the query.

Related