Reputation: 1202
I need to do a join with criteria builder and then to get result of Tuple
(Object[]
) type. First Tuple element should be Preke
(and this works correctly) and second Tuple
element should be a List<PrekeTiekejas>
containing @OneToMany
objects. Following code instead of List<PrekeTiekejas>
returns single PrekeTiekejas
object. What I did wrong?
CriteriaBuilder cb = MinutisManager.getInstance().getCriteriaBuilder();
CriteriaQuery<Tuple> criteriaQuery = cb.createTupleQuery();
Root<minutis.Preke> from = criteriaQuery.from(minutis.Preke.class);
ListJoin<minutis.Preke, minutis.PrekeTiekejas> tiekejai = from.joinList(Preke_.tiekejai.getName());
criteriaQuery.multiselect(from, tiekejai);
TypedQuery<Tuple> typedQuery = MinutisManager.getInstance().createQuery(criteriaQuery);
//pages
typedQuery.setFirstResult(0);
typedQuery.setMaxResults(100);
//typedQuery.setHint(QueryHints.REFRESH, HintValues.TRUE);
List<Tuple> tuples = typedQuery.getResultList();
for(Tuple t : tuples) {
minutis.Preke preke = t.get(0, minutis.Preke.class);
System.out.println(preke.getPavadinimas());
List<minutis.PrekeTiekejas> tiek = t.get(1, List.class);
System.out.println(tiek.size());
}
Here is the error I get:
Testcase: testGetPrekesByFilters(database.dao.PrekeDAOTest): Caused an ERROR
Element 1 type interface java.util.List is invalid for result "***PrekeTiekejas.toString()***".
java.lang.IllegalArgumentException: Element 1 type interface java.util.List is invalid for result "***PrekeTiekejas.toString()***".
at org.eclipse.persistence.internal.jpa.querydef.TupleImpl.get(TupleImpl.java:89)
at database.dao.PrekeDAOTest.testGetPrekesByFilters(PrekeDAOTest.java:69)
PrekeDAOTest.java:69
line:
List<minutis.PrekeTiekejas> tiek = t.get(1, List.class);
Upvotes: 2
Views: 3217
Reputation: 21190
JPA does not support returning collections as you are expecting, and instead returns a tuple for each Preke PrekeTiekejas pair. You will need to handle the results and build the List list yourself, or change what you are expecting.
Since you are querying for Preke entities which already have a collection mapping to PrekeTiekejas you could just return Preke and call getPrekeTiekejas() on each entity for the collection. Use root.fetch(Preke_.tiekejai.getName(), JoinType.LEFT) instead of the joinList in the query to ensure the related entities are fetched in the query. Something like:
CriteriaQuery<minutis.Preke> criteriaQuery = cb.createQuery(minutis.Preke.class);
Root<minutis.Preke> from = criteriaQuery.from(minutis.Preke.class);
from.fetch(Preke_.tiekejai.getName(), JoinType.LEFT);
criteriaQuery.select(from);//not really needed
TypedQuery<minutis.Preke> typedQuery = MinutisManager.getInstance().createQuery(criteriaQuery);
//pages
typedQuery.setFirstResult(0);
typedQuery.setMaxResults(100);
//typedQuery.setHint(QueryHints.REFRESH, HintValues.TRUE);
List<minutis.Preke> prekeList= typedQuery.getResultList();
for(minutis.Preke p : prekeList) {
System.out.println(preke.getPavadinimas());
List<minutis.PrekeTiekejas> tiek = preke.getTiekejai();//assumes tiekejai has a getTiekejai accessor
System.out.println(tiek.size());
}
Upvotes: 3