Getting list of lists in Hibernate
hibernate, java
Solution
Personally I would use the solution in plain java because it'll be more clear for any developer supporting your code in the future.
Answering the question "can it be done via Hibernate?": yes, it can be, ResultTransformer is the right way, especially if map-of-lists conversion is required more than once in your program. There is no standard transformer for your needs but you can write your own one:
public class MapOfListsResultTransformer<K, V> extends BasicTransformerAdapter {
public List transformList(List collection) {
final Map<K, List<V>> map = new HashMap<>();
for (Object object : collection) {
final Object[] objects = (Object[]) object;
final K key = (K) objects[0];
final V value = (V) objects[1];
if (!map.containsKey(key)) {
final List<V> list = new ArrayList<V>();
list.add(value);
map.put(key, list);
} else {
map.get(key).add(value);
}
}
return Arrays.asList(map);
}
}
And its usage is the following:
public Map<Integer, List<Integer>> findDisqualifiedDriversInRaces(List<Integer> raceIds) {
ProjectionList projection = Projections.projectionList()
.add(Projections.property("race.id").as("race.id"))
.add(Projections.property("startingNr").as("startingNr"));
return (Map<Integer, List<Integer>>) getSession()
.createCriteria(RaceDriver.class)
.setProjection(projection)
.add(Restrictions.in("race.id", raceIds))
.add(Restrictions.eq("disqualified", true))
.setResultTransformer(new MapOfListsResultTransformer<Integer, Integer>())
.uniqueResult();
}
Problem
In my project I have two entities: `Race` and `RaceDriver`, which has-a `Race` in it: ``` class RaceDriver { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "race", nullable = false) private Race race; ... @Column(name = "starting_nr") private Integer startingNr; ... @Column(name = "disqualified", nullable = false) private boolean disqualified; } ``` Now, what I wanted is to get the list of the `startingNr`s of the `disqualified` `RaceDriver`s in a `Race`, which looked like this: ``` public List<Integer> findDisqualifiedDriversStartingNumbers(Integer raceId) { ProjectionList projection = Projections.projectionList() .add(Projections.property("startingNr").as("startingNr")); return getSession() .createCriteria(RaceDriver.class) .setProjection(projection) .add(Restrictions.eq("race.id", raceId)) .add(Restrictions.eq("disqualified", true)) .list(); } ``` The thing is that now I need the same, but for the few `Races`. How can I achieve this without making a separate DAO calls? Because I've heard that it is better to make as much as possible in a single database call. My idea is to simply get the list of the drivers which are disqualified in the given races, and then parse it in the Java code, which I think will require few loops, and make some map of disqualified `RaceDriver`'s starting numbers, where the key would be `Race.id`. The DAO attempt looks like that: ``` public List<RaceDriver> findDisqualifiedDriversInRaces(List<Integer> raceIds) { return getSession() .createCriteria(RaceDriver.class) .add(Restrictions.in("race.id", raceIds)) .add(Restrictions.eq("disqualified", true)) .list(); } ``` The problem is that I will get that big objects, instead of some map or list of the only data I need (`startingNr` and `race.id`). So the question is - can I do it somehow using only Hibernate?