Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collections in QueryDSL projections

I am trying to use a projection to pull in data from an entity an some relations it has. However. The constructor on the projection takes three arguments; a set, integer and another integer. This all works fine if I don't have the set in there as an argument, but as soon as I add the set, I start getting SQL syntax query errors.

Here is an example of what I'm working with...

@Entity
public class Resource {
    private Long id;
    private String name;
    private String path;
    @ManyToOne
    @JoinColumn(name = "FK_RENDITION_ID")
    private Rendition rendition;
}

@Entity
public class Document {
    private Long id;
    private Integer pageCount;
    private String code;
}

@Entity
public class Rendition {
    Long id;
    @ManyToOne
    @JoinColumn(name="FK_DOCUMENT_ID")
    Document doc;
    @OneToMany(mappedBy="rendition")
    Set<Resource> resources;
}

public class Projection {        
    @QueryProjection
    public Projection(Set<Resource> resources, Integer pageCount, String code) {
    }
}

Here is the query like what I am using (not exactly the same as this is a simplified version of what I'm dealing with)....

QRendition rendition = QRendition.rendition;
Projection projection = from(rendition)
    .where(rendition.document().id.eq(documentId)
        .and(rendition.resources.isNotEmpty())
        .limit(1)
        .singleResult(
            new QProjection(rendition.resources, 
                rendition.document().pageCount,
                rendition.document().code));

This query works fine as long as my projection class does not have the rendition.resources in it. If I try and add that in, I start getting malformed SQL errors (it changes the output sql so that it starts with this.

select . as col_0_0_

So, I guess my main question here is how do I include a Set as an object in a projection? Is it possible, or am I just doing something wrong here?

like image 364
davija Avatar asked Jun 14 '13 20:06

davija


1 Answers

Using collections in projections is unreliable in JPA. It is safer to join the collection and aggregate the results instead.

Querydsl can also be used for result aggregation http://www.querydsl.com/static/querydsl/3.2.0/reference/html/ch03s02.html#d0e1799

In your case something like this

QRendition rendition = QRendition.rendition;
Projection projection = from(rendition)
    .innerJoin(rendition.document, document) 
    .innerJoin(rendition.resources, resource)  
    .where(document.id.eq(documentId))
    .limit(1)
    .transform(
         groupBy(document.id).as(
            new QProjection(set(resources), 
                document.pageCount,
                document.code)));
like image 136
Timo Westkämper Avatar answered Nov 14 '22 12:11

Timo Westkämper