QueryDSL duplikat zmiennej identyfikacyjnej / błąd składni równości z dowolnym na Set?

Mam podmioty JPA opisane tutaj:QueryDSL Błąd składni JPA zawiera na Set?

Teraz staram się mieć wiele ograniczeńSet tags w jednym zapytaniu:

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

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

Po wykonaniu zapytania otrzymuję następujący wyjątek:

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

Próbowałem wstawićas("withTags") do zapytania, ale lokalizacje, które mogę zrobić, są następująceany() który wstawia AS w JPQL w niewłaściwym miejscu w odniesieniu do problemu duplikacji, który próbuję rozwiązać. I mogę to wstawić późniejtags ale potem dostajęSimpleExpression jako zwrot, na którym nie mogę wykonaćany().

Wszelkie inne myśli, jak można zapobiec powielaniu zmiennej identyfikacyjnej?

Ponadto przedstawione powyżej stwierdzenia działają tylko wtedy, gdy podaneSet withTags/withoutTags zawiera tylko jedną wartość. Jeśli występuje wiele wartości, zgłaszany jest następujący wyjątek:

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)

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

Na razie próbowałem obejść ten problem, używając następującej składni QueryDSL:

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

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

Pierwsza część działa jak urok, ale druga nie przynosi oczekiwanych rezultatów. Licencje z tagami obecnymi wwithoutTags nie są wykluczone z zestawu wyników, tak jak powinny być.

JPQL i SQL dla tego drugiego wyrażenia wyglądają tak:

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 wygląda dobrze dla mnie, ale SQL oczywiście zawodzi, jeśli licencja ma więcej niż jeden znacznik. Myślę więc, że jest to przypadek, w którym tłumaczenie EclipseLink zawodzi. Popatrzę, czy jest to znany błąd dla używanej wersji. Teza ta jest w pewnym stopniu wspierana przezZapytanie „NOT MEMBER OF” JPQL przy użyciu API kryteriów jednak w tym przypadku problem występuje tylko podczas używania creteria api, a nie JPQL. To błędne tłumaczenie nadal występuje w EclipseLink 2.4 RC 2. Oto w końcu obejście tego, co jest przeznaczone dla części „bez tagów”:

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

Pozdrawiam, Tilmann

questionAnswers(2)

yourAnswerToTheQuestion