I have the following entity structure: Business --> Campaign --> Promotion, where ONE Business can have MANY Campaigns and ONE Campaign can have MANY Promotions. Both one-to-man
I assume if you use a List, hibernate assumes that the order is important, and it will deduce the order of elements from the rows returned, but if you join with a nother table hibernate will get each campaign multiple times which confuses hibernate. Again, I am just assuming this
This is expected behavior Use a RootEntityResultTransformer to get a single root entity: http://www.hibernate.org/hib_docs/v3/api/org/hibernate/transform/RootEntityResultTransformer.html
Another workaround instead of using Set is to use two queries to get the data :- 1st one to load the campaign and its associated promotions of the business. Then load the Business and its campaigns using fetch
Query query1 = entityManager.createQuery("select c from Business b join b.campaigns c left join fetch c.promotions where b.id=:id");
query1.setParameter("id", b.getId());
query1.getResultList();
Query query2 = entityManager.createQuery("select b from Business b left join fetch b.campaigns where b.id=:id");
query2.setParameter("id", b.getId());
business = (Business) query2.getResultList().get(0);
The generated sql would look something like:
select * from Business b
left outer join campaigns c on c.business_id = b.id
left join promotions p on p.campaign_id = c.id
where b.id=:id
Internally Hibernate will have only one Business instance, however the duplicates will be preserved in the result set. This is expected behaviour. The behaviour you require can be acheived either by using the DISTINCT clause, or by using a LinkedHashSet to filter results:
Collection result = new LinkedHashSet(query.getResultList());
which will return only unique results, preserving insertion order.
The "org.hibernate.HibernateException: cannot simultaneously fetch multiple bags" happens whenever you try to eagerly fetch more than one collection in an ordered fashion (and possibly duplicated items). This does sort of make sense if you consider the generated SQL. Hibernate has no way of knowing whether a duplicated object was caused by the join or by actual duplicate data in the child table. Look at this for a good explanation.