Hi. I'm having a problem using query projections. Basically the
list(Expr) method of the query returns an ArrayList of Object[]
containing constructor args of my DTO.
QueryDSL version in use 1.8.4.
This is my DTO:
public class UzemniCelek implements Serializable {
@QueryProjection
public UzemniCelek(Long key, String id, String popis) {
this.key = key;
this.id = id;
this.popis = popis;
}
...
This is the query construction:
JPAQuery q = new JPAQuery(em);
QObvodView ov = QObvodView.obvodView;
q.from(ov);
...
QUzemniCelek uc = new QUzemniCelek( ov.krajKey, ov.krajId, ov.krajPopis);
Object o = q.list(uc);
Variable uc evaluates to: new UzemniCelek(obvodView.krajKey, obvodView.krajId, obvodView.krajPopis)
But the finally issued query looks like this:
Hibernate:
/* select
obvodView.krajKey,
obvodView.krajId,
obvodView.krajPopis
from
ObvodView obvodView
order by
obvodView.krajId asc */
The resulting list is not a List<UzemniCelek>, it's a list of arrays of objects containing values of the selected rows.
What am I doing wrong.
Thanks for your replay
JaPe
timowestYou are doing everything right. This is a bug in the JPAQuery's handling of constructor expressions. I am fixing it right now.
peremskyThis is a workaround I found:
...
EConstructor<UzemniCelek> uc = null;
uc = QUzemniCelek
.create(UzemniCelek.class, ov.krajKey, ov.krajId, ov.krajPopis);
return q.list(uc);
...
JaPe
timowestFix commited to SVN trunk
Fixed in 1.9.0
mwalterI thought this bug is fixed?
I'm using
Querydsl 2.1.2 with OpenJPA 1.2.3 and I get a list of Object arrays returned using the static create() method as peremsky described.
I
tried the workaround using class ConstructorExpression because
EConstructor does not exist anymore. But the class ConstructorExpression
does not accept my entity class as a parameter.
So what can I do now? Please help! Thank you!
Edit:
I
tried the constructor projection with a plain POJO and it worked. But
if the @QueryProjection annotated class is an JPA entity as well,
it does not work! So please fix that! Same problem as peremsky had before.
timowestCould you post the executed JPQL query?
> But the class ConstructorExpression does not accept my entity class as a parameter.
What do you mean by that?
I
believe your problem is caused by the fact the Querydsl JPA does not
yet support custom projections for other backends then Hibernate.
We have tested Querydsl JPA with Hibernate and EclipseLink, not OpenJPA.
Is
there a specific API to declare custom projections / result
transformation in OpenJPA? I believe this is not yet covered by the JPA 2
specs.
mwalterFirst of all, we are using JPA 1.0
Here is the query Querydsl generates:
SELECT t0.VM_ART_ID, t0.VM_ART_ABK, t0.VM_ID, t0.VM_NR, t0.VM_LAUF_ID, t0.VM_LAUF_VARIANTE, t0.VP_NR, t0.BP_VON_ID, t0.BP_VON_BEZEICHNUNG, t0.BP_NACH_ID, t0.BP_NACH_BEZEICHNUNG, t0.VM_LAUF_ELEMENT_VON_AB_ZEIT, t0.VM_LAUF_ELEMENT_NACH_AN_ZEIT, t0.VM_STRECKE_ID, t0.VM_LINIE_ID, t0.VM_LINIE_NR, t0.TU_ID, t0.TU_CODE, t0.VM_LAUF_PLANUNGSTYP_CODE_ID, t0.VM_LAUF_OEFFENTLICH_TF, t0.VM_LAUF_GUELTIG_TF, t0.VM_LAUF_GELOESCHT_TF, t0.FPL_PERIODE_ID, t0.DATENQUELLE_ID
from vw_vm_suche t0
where (t0.vm_nr = '1061')
GROUP BY t0.VM_ART_ID, t0.VM_ART_ABK, t0.VM_ID, t0.VM_NR, t0.VM_LAUF_ID, t0.VM_LAUF_VARIANTE, t0.VP_NR, t0.BP_VON_ID, t0.BP_VON_BEZEICHNUNG, t0.BP_NACH_ID, t0.BP_NACH_BEZEICHNUNG, t0.VM_LAUF_ELEMENT_VON_AB_ZEIT, t0.VM_LAUF_ELEMENT_NACH_AN_ZEIT, t0.VM_STRECKE_ID, t0.VM_LINIE_ID, t0.VM_LINIE_NR, t0.TU_ID, t0.TU_CODE, t0.VM_LAUF_PLANUNGSTYP_CODE_ID, t0.VM_LAUF_OEFFENTLICH_TF, t0.VM_LAUF_GUELTIG_TF, t0.VM_LAUF_GELOESCHT_TF, t0.FPL_PERIODE_ID, t0.DATENQUELLE_ID
First thing, JPA constructor expressions use the following syntax:
SELECT NEW <fully qualified class name> ...
In the generated query above I do not see a NEW operator.
Second, the query should return a list of VwVmSucheDto objects:
return query.list(new QVwVmSucheDto(...))
Here is the generated constructor:
public QVwVmSucheDto(NumberExpression<Long> vmArtId, StringExpression vmArtAbk, NumberExpression<Long> vmId, StringExpression vmNr, NumberExpression<Long> vmLaufId, NumberExpression<Integer> vmLaufVariante, NumberExpression<Integer> vpNr, NumberExpression<Long> bpVonId, StringExpression bpVonBezeichnung, NumberExpression<Long> bpNachId, StringExpression bpNachBezeichnung, DateTimeExpression<? extends java.util.Calendar> vmLaufElementVonAbZeit, DateTimeExpression<? extends java.util.Calendar> vmLaufElementNachAnZeit, NumberExpression<Long> vmStreckeId, NumberExpression<Long> vmLinieId, StringExpression vmLinieNr, NumberExpression<Long> tuId, StringExpression tuCode, NumberExpression<Long> vmLaufPlanungstypCodeId, BooleanExpression vmLaufOeffentlich, BooleanExpression vmLaufGueltig, BooleanExpression vmLaufGeloescht, NumberExpression<Long> fplPeriodeId, NumberExpression<Long> datenquelleId) {
super(VwVmSucheDto.class, new Class[]{Long.class, String.class, Long.class, String.class, Long.class, Integer.class, Integer.class, Long.class, String.class, Long.class, String.class, java.util.Calendar.class, java.util.Calendar.class, Long.class, Long.class, String.class, Long.class, String.class, Long.class, Boolean.class, Boolean.class, Boolean.class, Long.class, Long.class}, vmArtId, vmArtAbk, vmId, vmNr, vmLaufId, vmLaufVariante, vpNr, bpVonId, bpVonBezeichnung, bpNachId, bpNachBezeichnung, vmLaufElementVonAbZeit, vmLaufElementNachAnZeit, vmStreckeId, vmLinieId, vmLinieNr, tuId, tuCode, vmLaufPlanungstypCodeId, vmLaufOeffentlich, vmLaufGueltig, vmLaufGeloescht, fplPeriodeId, datenquelleId);
}
If the query is executed I get an ArrayList which contains objects filled with the values instead of VwVmSucheDto.

But this is quite clear because in the generated constructor new
Class[]{...} is called which creates Object[]. Shouldn't it read new
VwVmSucheDto here?
timowestCould you try updating to SVN trunk?
I just fixed some issues with custom projections and non-Hibernate JPA providers. Here is a related ticket :
https://bugs.launchpad.net/querydsl/+bug/542913I am aware of the JPQL constructor expressions, but we needed a more general contract for FactoryExpressions.
mwalterI checked out the latest sources and startet the build in querydsl-root with mvn install. This is the result:
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] Querydsl .......................................... SUCCESS [13.641s]
[INFO] Querydsl - Core module ............................ SUCCESS [1:44.000s]
[INFO] Querydsl - APT support ............................ SUCCESS [2:21.000s]
[INFO] Querydsl - Collections support .................... SUCCESS [29.203s]
[INFO] Querydsl - SQL support ............................ FAILURE [6:04.406s]
[INFO] Querydsl - Maven plugin ........................... SKIPPED
[INFO] Querydsl - JPA support ............................ SKIPPED
[INFO] Querydsl - JDO support ............................ SKIPPED
[INFO] Querydsl - Lucene support ......................... SKIPPED
[INFO] Querydsl - Hibernate Search support ............... SKIPPED
[INFO] Querydsl - Mongodb support ........................ SKIPPED
[INFO] Querydsl - Scala support .......................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 10:52.656s
[INFO] Finished at: Wed Jul 06 12:02:31 CEST 2011
[INFO] Final Memory: 46M/80M
[INFO] ------------------------------------------------------------------------
[ERROR]
Failed to execute goal on project querydsl-sql: Could not resolve
dependencies for project
com.mysema.querydsl:querydsl-sql:jar:2.2.0.beta5-SNAPSHOT: Fa
iled to
collect dependencies for
[com.mysema.querydsl:querydsl-core:jar:2.2.0.beta5-SNAPSHOT (compile),
org.slf4j:slf4j-api:jar:1.6.1 (compile), org.slf4j:slf4j
-log4j12:jar:1.6.1
(provided), joda-time:joda-time:jar:1.6 (compile),
javax.validation:validation-api:jar:
1.0.0.GA (compile),
org.apache.ant:ant:jar:1.8.1 (prov
ided), hsqldb:hsqldb:jar:1.8.0.10
(test), org.apache.derby:derby:jar:10.8.1.2 (test),
mysql:mysql-connector-java:jar:5.1.16 (test),
postgresql:postgresql:jar:8.
4-701.jdbc4 (test),
com.oracle:ojdbc5:jar:11.1.0.7.0 (test),
net.sourceforge.jtds:jtds:jar:1.2.4 (test),
com.h2database:h2:jar:1.3.157 (test), com.mysema.queryd
sl:querydsl-core:jar:tests:2.2.0.beta5-SNAPSHOT
(test), commons-io:commons-io:jar:1.4 (test), jdepend:jdepend:jar:2.9.1
(test), junit:junit:jar:4.8.1 (test), or
g.easymock:easymock:jar:3.0
(test)]: Failed to read artifact descriptor for
com.oracle:ojdbc5:jar:11.1.0.7.0: Could not transfer artifact
com.oracle:ojdbc5:pom:
11.1.0.7.0 from/to jahia (
http://maven.jahia.org/maven2): Error transferring file: Connection reset -> [Help 1]
Edit: Okay, the jahia server is down.
Can you provide the JAR somewhere?
timowestI just uploaded the latest snapshot to our repo :
http://source.mysema.com/maven2/snapshots/mwalterOkay, thank you very much! You are very fast!
Update:I found out new interesting things:
The constructor used by Querydsl is very restrictive i.e. the constructor generated by Querydsl uses wrapper types
only and always. But our DTO's constructor looks like that:
@QueryProjection
public VwVmSucheDto(final Long vmArtId, final String vmArtAbk, final Long vmId, final String vmNr, final Long vmLaufId, final int vmLaufVariante,
final int vpNr, final Long bpVonId, final String bpVonBezeichnung, final Long bpNachId, final String bpNachBezeichnung,
final Calendar vmLaufElementVonAbZeit, final Calendar vmLaufElementNachAnZeit, final Long vmStreckeId, final Long vmLinieId,
final String vmLinieNr, final Long tuId, final String tuCode, final Long vmLaufPlanungstypCodeId, final boolean vmLaufOeffentlich,
final boolean vmLaufGueltig, final boolean vmLaufGeloescht, final Long fplPeriodeId, final Long datenquelleId) {
...
}
As you can see we use some primitive values here. But Querydsl simply ignores that and generates this instead:
public QVwVmSucheDto(NumberExpression<Long> vmArtId, StringExpression vmArtAbk, NumberExpression<Long> vmId, StringExpression vmNr, NumberExpression<Long> vmLaufId, NumberExpression<Integer> vmLaufVariante, NumberExpression<Integer> vpNr, NumberExpression<Long> bpVonId, StringExpression bpVonBezeichnung, NumberExpression<Long> bpNachId, StringExpression bpNachBezeichnung, DateTimeExpression<? extends java.util.Calendar> vmLaufElementVonAbZeit, DateTimeExpression<? extends java.util.Calendar> vmLaufElementNachAnZeit, NumberExpression<Long> vmStreckeId, NumberExpression<Long> vmLinieId, StringExpression vmLinieNr, NumberExpression<Long> tuId, StringExpression tuCode, NumberExpression<Long> vmLaufPlanungstypCodeId, BooleanExpression vmLaufOeffentlich, BooleanExpression vmLaufGueltig, BooleanExpression vmLaufGeloescht, NumberExpression<Long> fplPeriodeId, NumberExpression<Long> datenquelleId) {
super(VwVmSucheDto.class, new Class[]{Long.class, String.class, Long.class, String.class, Long.class, Integer.class, Integer.class, Long.class, String.class, Long.class, String.class, java.util.Calendar.class, java.util.Calendar.class, Long.class, Long.class, String.class, Long.class, String.class, Long.class, Boolean.class, Boolean.class, Boolean.class, Long.class, Long.class}, vmArtId, vmArtAbk, vmId, vmNr, vmLaufId, vmLaufVariante, vpNr, bpVonId, bpVonBezeichnung, bpNachId, bpNachBezeichnung, vmLaufElementVonAbZeit, vmLaufElementNachAnZeit, vmStreckeId, vmLinieId, vmLinieNr, tuId, tuCode, vmLaufPlanungstypCodeId, vmLaufOeffentlich, vmLaufGueltig, vmLaufGeloescht, fplPeriodeId, datenquelleId);
}
As you can see in the line super(...) every value is a wrapper type, no primitives here.
Now
if I execute a query using query projection I get
java.lang.NoSuchMethodException: VwVmSucheDto.<init>(...) because
the constructors do not match!
I got it to work with
2.2.0.beta5-SNAPSHOT by manually changing all the primitives to their
wrapper types respectively. But this it not the way it was designed to,
is it?
timowestCould you file a bug on this?
> But this it not the way it was designed to, is it?
No ;)
mwalterOkay, bug is reported:
#806838Is there a chance that you will fix it in the next release?
timowestYes, this will be probably fixed for the next release.