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?

Original source