¿QueryDSL duplicó la variable de identificación / error de sintaxis de igualdad con alguno en Set?
Tengo entidades JPA como se describe aquí:¿El error de sintaxis QueryDSL JPA con contiene en Set?
Ahora trato de tener múltiples restricciones en elSet tags
en una sola consulta:
Set<Tag> withTags = ...;
Set<Tag> withoutTags = ...;
q.where(license.tags.any().in(withTags));
q.where(license.tags.any().in(withoutTags).not());
Cuando se ejecuta la consulta obtengo la siguiente excepción:
Exception [EclipseLink-8019] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Error compiling the query [select distinct license
from License license
where exists (select license_tags
from Tag license_tags
where license_tags member of license.tags and license_tags = ?1)
and not exists (select license_tags
from Tag license_tags
where license_tags member of license.tags and license_tags = ?2)]
multiple declaration of identification variable [license_tags], previously declared as [Tag license_tags].
Traté de insertaras("withTags")
en la consulta, pero las ubicaciones que puedo hacer eso es despuésany()
que inserta el AS en JPQL en el lugar equivocado con respecto al problema de duplicación que estoy tratando de resolver. Y puedo insertarlo despuéstags
pero luego me sale unSimpleExpression
como retorno sobre el que no puedo ejecutarany()
.
¿Alguna otra idea de cómo podría evitarse esta duplicación de la variable de identificación?
Además, las declaraciones presentadas anteriormente solo funcionan si elSet
withTags
/withoutTags
contiene un solo valor Si hay varios valores presentes, se lanza la siguiente excepción:
Exception [EclipseLink-6075] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.QueryException
Exception Description: Object comparisons can only use the equal() or notEqual() operators. Other comparisons must be done through query keys or direct attribute level comparisons.
Expression: [Relation operator IN Base my.package.Tag Parameter 1]
select distinct license
from License license
where exists (select license_tags
from Tag license_tags
where license_tags member of license.tags and license_tags in ?1)
at org.eclipse.persistence.exceptions.QueryException.invalidOperatorForObjectComparison(QueryException.java:614)
at org.eclipse.persistence.internal.expressions.RelationExpression.normalize(RelationExpression.java:393)
at org.eclipse.persistence.internal.expressions.CompoundExpression.normalize(CompoundExpression.java:226)
at org.eclipse.persistence.internal.expressions.CompoundExpression.normalize(CompoundExpression.java:218)
at org.eclipse.persistence.internal.expressions.SQLSelectStatement.normalize(SQLSelectStatement.java:1306)
at org.eclipse.persistence.internal.expressions.SubSelectExpression.normalizeSubSelect(SubSelectExpression.java:134)
at org.eclipse.persistence.internal.expressions.ExpressionNormalizer.normalizeSubSelects(ExpressionNormalizer.java:93)
at org.eclipse.persistence.internal.expressions.SQLSelectStatement.normalize(SQLSelectStatement.java:1379)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.buildNormalSelectStatement(ExpressionQueryMechanism.java:482)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.prepareSelectAllRows(ExpressionQueryMechanism.java:1553)
at org.eclipse.persistence.queries.ReadAllQuery.prepareSelectAllRows(ReadAllQuery.java:793)
at org.eclipse.persistence.queries.ReadAllQuery.prepare(ReadAllQuery.java:734)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:464)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.checkPrepare(ObjectLevelReadQuery.java:732)
at org.eclipse.persistence.queries.DatabaseQuery.prepareCall(DatabaseQuery.java:1577)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:240)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:173)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:125)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:109)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1326)
at sun.reflect.GeneratedMethodAccessor552.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:304)
at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:54)
at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:163)
at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:298)
at org.jboss.weld.bean.proxy.ClientProxyMethodHandler.invoke(ClientProxyMethodHandler.java:113)
at org.jboss.weld.util.CleanableMethodHandler.invoke(CleanableMethodHandler.java:43)
at javax.persistence.EntityManager_$_javassist_131.createQuery(EntityManager_$_javassist_131.java)
at com.mysema.query.jpa.impl.DefaultSessionHolder.createQuery(DefaultSessionHolder.java:35)
at com.mysema.query.jpa.impl.AbstractJPAQuery.createQuery(AbstractJPAQuery.java:139)
at com.mysema.query.jpa.impl.AbstractJPAQuery.createQuery(AbstractJPAQuery.java:108)
at com.mysema.query.jpa.impl.AbstractJPAQuery.list(AbstractJPAQuery.java:276)
Y con EclipseLink 2.4.
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: The SQL datatype to be used for an instance of mypackage.Tag cannot be determined. Use 'setObject()' with an explizit type, to define it.
Error Code: 0
Call: SELECT DISTINCT t0.ID, ...all the other properties...
FROM LICENSE t0, WHERE ((NOT EXISTS (SELECT ? FROM LicenseTags t5, TAG t4, TAG t3 WHERE (((t3.ID = t4.ID) AND (t3.ID IN (?,?))) AND ((t5.License_ID = t0.ID) AND (t4.ID = t5.tags_ID))))))
Por ahora, intenté solucionar esto utilizando la siguiente sintaxis de QueryDSL:
for (Tag tag : withTags) {
q.where(license.tags.contains(tag));
}
for (Tag tag : withoutTags) {
q.where(license.tags.contains(tag).not());
}
La primera parte funciona a la perfección, pero la última no devuelve los resultados esperados. Licencias con etiquetas presentes enwithoutTags
no se excluyen del conjunto de resultados como deberían ser.
JPQL y SQL para la última declaración parecen:
select distinct license
from License license
where not ?1 member of license.tags
SELECT DISTINCT t1.ID, ...all the other properties...
FROM LicenseTags t2, LICENSE t1, TAG t0
WHERE (NOT (133170 = t0.ID) AND (t2.License_ID = t1.ID) AND (t0.ID = t2.tags_ID))
El JPQL me parece bien, pero el SQL obviamente falla si una licencia tiene más de una etiqueta asociada. Así que creo que este es realmente un caso donde la traducción de EclipseLink está fallando. Voy a echar un vistazo si este es un error conocido para la versión que estoy usando. Esta tesis está algo apoyada porConsulta de JPQL "NO MIEMBRO DE" que utiliza criterios API aunque en ese caso, el problema solo se produce cuando se utiliza creteria api y no JPQL. Esta traducción errónea aún persiste en EclipseLink 2.4 RC 2. Esta es finalmente una solución que hace lo que significa para la parte "sin etiquetas":
Collection<Integer> tagIds = new ArrayList<Integer>();
for (Tag tag : withoutTags) {
tagIds.add(tag.getId());
}
q.where(license.tags.any().id.in(tagIds).not());
Un saludo, Tilmann