Reputation: 66
QueryDsl provides a tool for aggregating results returned from the database as follows:
http://www.querydsl.com/static/querydsl/latest/reference/html/ch03s02.html
In the item: 3.2.4. Result aggregation
But I don't know how to do a 3-level aggregation, and I didn't find any documentation of it, nor in the QueryDSL automated test class does this case appear, and it seems very strange that this is not possible, as this is a very common case.
Here's the example of what I want to do:
DTO's classes :
class DtoLevel1 {
Long id;
List<DtoLevel2> level2;
}
class DtoLevel2 {
Long id;
List<DtoLevel3> level3;
}
class DtoLevel3 {
Long id;
}
Query:
QDtoLevel1 dtoLevel1 = QDtoLevel1.dtoLevel1;
QDtoLevel1 dtoLevel2 = QDtoLevel1.dtoLevel1;
QDtoLevel1 dtoLevel3 = QDtoLevel1.dtoLevel1;
JPAQuery<DtoLevel1> query = new JPAQuery<DtoLevel1>();
// ... query.from, etc
query.transform(
GroupBy.groupBy(dtoLevel1.id).as( // the first level is ok
Projections.constructor(
DtoLevel1.class, dtoLevel1.id,
GroupBy.list( // passing grouped items in the first level
Projections.constructor(
DtoLevel2.class,
dtoLevel2.id,
GroupBy.groupBy(dtoLevel2.id) // the problem is here
.list(
Projections.constructor(DtoLevel3.class, dtoLevel3.id)
)
)
)
)
)
)
In the line where I highlighted my problem, is a conceptual code that is the way I believe it should work. Which is where I need to group the third level items belonging to the current second level, but I haven't found a way to do that, just for the first level.
Upvotes: 2
Views: 1260
Reputation: 11
Djefferson, I faced this problem too. Seems actually this problem has no solution yet. Multiple level support is a feature to do in QueryDsl roadmap, but is foreseen since 2015..
I developed a lib to offer a approach to help this multiple level aggregation. More details in: https://github.com/zisluiz/querydsl-object-binder.
Below a example that how this lib can help a aggregation like that:
JPAQuery<Tuple> query = new JPAQuery<Tuple>(em);
query.from(_city)
.join(_city.state, _state)
.join(_state.country, _country);
List<Tuple> tupleResult = query.select(_city.id, _city.name,
_state.id, _state.name,
_country.id, _country.name).orderBy(_city.id.asc()).fetch();
List<City> cities = QueryDslBinder.to(tupleResult, City.class,
new GroupByBinder()
.key("id", _city.id).
field("name", _city.name)
.single("state", new GroupByBinder()
.key("id", _state.id)
.field("name", _state.name)
.single("country", new GroupByBinder()
.key("id", _country.id)
.field("name", _country.name)
.collection("states", new GroupByBinder()
.key("id", _state.id)))));
It supports a variety of queries combinations in multiple levels, always using single object referente for each specified object. Supports too subquery expressions path and many complex queries that are not possible to map into results with only QueryDsl api. Helped me a lot in company project.
Upvotes: 1