Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate - sqlQuery map redundant records while using JOIN on OneToMany

I have @OneToMany association between 2 entities (Entity1 To Entity2).

My sqlQueryString consists of next steps:

  • select ent1.*, ent2.differ_field from Entity1 as ent1 left outer join Entity2 as ent2 on ent1.item_id = ent2.item_id
  • Adding some subqueries and writing results to some_field2, some_field3 etc.


Execute:

Query sqlQuery = getCurrentSession().createSQLQuery(sqlQueryString)
                 .setResultTransformer(Transformers.aliasToBean(SomeDto.class));

List list = sqlQuery.list();

and

class SomeDto {
    item_id;
    some_filed1;
    ...
    differ_field;
    ...

}

So the result is the List<SomeDto>

enter image description here

Fields which are highlighted with grey are the same.

So what I want is to group by, for example, item_id and the List<Object> differFieldList would be as aggregation result.

class SomeDto {

 ...fields...

 List<Object> differFieldList;

}

or something like that Map<SomeDto, List<Object>>

I can map it manually but there is a trouble: When I use sqlQuery.setFirstResult(offset).setMaxResults(limit) I retrieve limit count of records. But there are redundant rows. After merge I have less count actually.

Thanks in advance!

like image 425
InsFi Avatar asked Aug 12 '15 21:08

InsFi


1 Answers

If you would like to store the query results in a collection of this class:

class SomeDto {
 ...fields...
 List<Object> differFieldList;
}

When using sqlQuery.setFirstResult(offset).setMaxResults(n), the number of records being limited is based on the joined result set. After merging the number of records could be less than expected, and the data in List could also be incomplete.

To get the expected data set, the query needs to be broken down into two.

In first query you simply select data from Entity1

select * from Entity1

Query.setFirstResult(offset).setMaxResults(n) can be used here to limit the records you want to return. If fields from Entity2 needs to be used as condition in this query, you may use exists subquery to join to Entity2 and filter by Entity2 fields.

Once data is returned from the query, you can extract item_id and put them into a collection, and use the collection to query Entity 2:

select item_id, differ_field from Entity2 where item_id in (:itemid)

Query.setParameterList() can be used to set the item id collection returned from first query to the second query. Then you will need to manually map data returned from query 2 to data returned from query 1.

This seems verbose. If JPA @OneToMany mapping is configured between the 2 entity objects, and your query can be written in HQL (you said not possible in comment), you may let Hibernate lazy load Entity2 collection for you automatically, in which case the code can be much cleaner, but behind the scenes Hibernate may generate more query requests to DB while lazy loading the entity sitting at Many side.

like image 117
JM Yang Avatar answered Oct 10 '22 13:10

JM Yang