QueryDSL重复标识变量/相等语法错误,是否存在Set? [英] QueryDSL duplicate identification variable/equality syntax error with any on Set?

查看:126
本文介绍了QueryDSL重复标识变量/相等语法错误,是否存在Set?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有JPA实体,如下所示: 在集合中包含的QueryDSL JPA语法错误?

现在,我尝试在单个查询中对Set tags进行多个限制:

Set<Tag> withTags = ...;
Set<Tag> withoutTags = ...;

q.where(license.tags.any().in(withTags));
q.where(license.tags.any().in(withoutTags).not());

执行查询时,出现以下异常:

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].

我试图在查询中插入as("withTags"),但是我可以做的位置是在any()之后,该位置将AS插入JPQL中关于我要解决的复制问题的错误位置.我可以在tags之后插入它,但随后得到一个SimpleExpression作为返回值,无法执行any().

还有其他想法如何防止标识变量的重复?

此外,上面给出的语句仅在给定的Set withTags/withoutTags仅包含单个值的情况下起作用.如果存在多个值,则会引发以下异常:

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)

使用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))))))

目前,我尝试使用以下QueryDSL语法解决此问题:

for (Tag tag : withTags) {
    q.where(license.tags.contains(tag));
}

for (Tag tag : withoutTags) {
    q.where(license.tags.contains(tag).not());
}

前一部分的确起到了魅力的作用,但后者没有返回预期的结果. withoutTags中带有标签的许可证不会像应有的那样被排除在结果集中.

后一个语句的JPQL和SQL看起来像:

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))

JPQL对我来说看起来不错,但是如果许可证具有多个关联的标签,则SQL显然会失败.因此,我认为这实际上是EclipseLink的翻译失败的情况.我将看看这是否是我使用的版本的已知错误. JPQL"NOT MEMBER OF"使用条件API 进行查询,尽管在这种情况下,仅在使用creteria API而不是JPQL时才会出现问题.这种错误翻译仍然存在于EclipseLink 2.4 RC 2中.这是一种最终的解决方法,可以实现无标签"部分的目的:

Collection<Integer> tagIds = new ArrayList<Integer>();
for (Tag tag : withoutTags) {
    tagIds.add(tag.getId());
}
q.where(license.tags.any().id.in(tagIds).not());

问候,蒂尔曼

解决方案

当前EclipseLink和QueryDSL中的错误拒绝使用直接语句:

q.where(license.tags.any().in(withTags));
q.where(license.tags.any().in(withoutTags).not());

相反,必须使用一种解决方法:

Collection<Integer> withTagIds = new ArrayList<Integer>();
for (Tag tag : withTags) {
    withTagIds.add(tag.getId());
}
q.where(license.tags.any().id.in(withTagIds));

Collection<Integer> withoutTagIds = new ArrayList<Integer>();
for (Tag tag : withoutTags) {
    withoutTagIds .add(tag.getId());
}
q.where(license.tags.any().id.in(withoutTagIds ).not());

I have JPA entities as outlined here: QueryDSL JPA syntax error with contains on Set?

Now I try to have multiple restrictions on the Set tags in a single query:

Set<Tag> withTags = ...;
Set<Tag> withoutTags = ...;

q.where(license.tags.any().in(withTags));
q.where(license.tags.any().in(withoutTags).not());

When the query is executed I get the following exception:

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].

I tried to insert as("withTags") into the query but the locations I can do that is is after any() which inserts the the AS in JPQL in the wrong place regarding the duplication problem I am trying to solve. And I can insert it after tags but then I get a SimpleExpression as return on which I cannot execute any().

Any other thoughts how this duplication of identification variable could be prevented?

In addition the statements presented above do only work if the given Set withTags/withoutTags contains only a single value. If multiple values are present the following exception is thrown:

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)

And with 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))))))

For now I tried to work around this by using the following QueryDSL syntax:

for (Tag tag : withTags) {
    q.where(license.tags.contains(tag));
}

for (Tag tag : withoutTags) {
    q.where(license.tags.contains(tag).not());
}

The former part does work like a charm but the latter does not return the expected results. Licenses with tags present in withoutTags are not excluded from the result set as they should be.

JPQL and SQL for the latter statement look like:

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))

The JPQL looks good to me, but the SQL obviously fails if a license has more than one tag associated with it. So I think this is actually a case where the translation of EclipseLink is failing. I'll have a look if this is a known bug for the version I am using. This thesis is somewhat supported by JPQL "NOT MEMBER OF" query using criteria API though in that case the problem only occurs while using creteria api and not JPQL. This erroneous translation still persists in EclipseLink 2.4 RC 2. Here is finally a workaround that does what it's meant to for the part "without tags":

Collection<Integer> tagIds = new ArrayList<Integer>();
for (Tag tag : withoutTags) {
    tagIds.add(tag.getId());
}
q.where(license.tags.any().id.in(tagIds).not());

Regards, Tilmann

解决方案

Currently there are bugs in EclipseLink and QueryDSL that deny usage of the straight forward statements:

q.where(license.tags.any().in(withTags));
q.where(license.tags.any().in(withoutTags).not());

Instead a workaround has to be used:

Collection<Integer> withTagIds = new ArrayList<Integer>();
for (Tag tag : withTags) {
    withTagIds.add(tag.getId());
}
q.where(license.tags.any().id.in(withTagIds));

Collection<Integer> withoutTagIds = new ArrayList<Integer>();
for (Tag tag : withoutTags) {
    withoutTagIds .add(tag.getId());
}
q.where(license.tags.any().id.in(withoutTagIds ).not());

这篇关于QueryDSL重复标识变量/相等语法错误,是否存在Set?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆