Support custom row-mapping projections

Bug #809289 reported by Osvaldas Grigas
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Querydsl
Fix Released
Undecided
Unassigned

Bug Description

I do not use DTO generation. For projecting query results into domain objects, I normally use either QBean or ConstructorExpression. However, there are times when these two do not provide enough flexibility, for example, when I need to transform row data in some way before putting it into the domain object.

In these cases, I'd like to be able to implement something like Spring's RowMapper interface for manual projection logic, only instead of ResultSet it should be strongly typed just like everything else in Querydsl, so that I could write things like:

QUserGroup ug = QUserGroup.userGroup;
from(ug).list(new MappingProjection<UserGroup, QUserGroup>(UserGroup.class, ug) {
    protected UserGroup map(Tuple row, QUserGroup columns) {
        UserGroup group = new UserGroup();
        group.setId(row.get(columns.id));
        group.setName(row.get(columns.name));
        group.setRoles(row.get(columns.roles).split(","));
        return group;
    }
});

Tags: projection
Revision history for this message
Osvaldas Grigas (o-grigas) wrote :

I've attached a rather compact working prototype of MappingProjection - which is a FactoryExpression based on QTuple. Maybe I'm missing something, but I couldn't find an easier way to do that in Querydsl 2.2.0-beta4.

If you think it would make sense to include it into Querydsl (in one form or another), please do so. Also I would be very much interested to hear your opinion: is it the best way to go or do you see alternative solutions.

Revision history for this message
Timo Westkämper (timo-westkamper) wrote :

This is a very good addition, butI will generalize it a bit.

This should also work when using columns from multiple tables.

Maybe MappingProjection would just be an adapter to QTuple for further projection.

final QUserGroup ug = QUserGroup.userGroup;
MappingProjection<UserGroup> projection = new MappingProjection<UserGroup>(UserGroup.class, ug.all()){
    protected UserGroup map(Tuple row) {
        UserGroup group = new UserGroup();
        group.setId(row.get(ug.id));
        group.setName(row.get(ug.name));
        group.setRoles(row.get(ug.roles).split(","));
        return group;
    }
};

Revision history for this message
Luis Fernando Planella Gonzalez (luisfpg) wrote :

Seems nice.
The only thing to note is that QTuple currently has multiple constructors, and all those should be added to MappingProjection as well...

Revision history for this message
Osvaldas Grigas (o-grigas) wrote :

Updated the attached prototype implementation:
- generalized for multiple tables as Timo suggested
- added multiple constructors as Luis suggested
- added some JavaDocs

Revision history for this message
Osvaldas Grigas (o-grigas) wrote :

Other projections currently have a factory method that infers the generic type
argument and allows for a less verbose instantiation,
e.g. instead of: new ConstructorExpression<UserGroup>(UserGroup.class, ...);
  one can write: Projections.constructor(UserGroup.class, ...);

For the sake of consistency, I thought it would be nice to also have something
like that for MappingProjection (Projections.mapping(...)), but then I'm not
sure if it's possible to do with an abstract class.

Revision history for this message
Timo Westkämper (timo-westkamper) wrote :

Fix commited.

Changed in querydsl:
status: New → Fix Committed
Revision history for this message
Timo Westkämper (timo-westkamper) wrote :

Released in 2.2.0

Changed in querydsl:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.