2017-01-12 2 views
1

Betrachten Sie die folgende JPA Entity (Implementierung ist Hibernate 4.3.0):Warum funktioniert dieser enum-Parameter für ein einzelnes Feld und nicht für eine Sammlung?

@Entity 
public class MyEntity { 

    @Id 
    protected long myEntityId; 

    @Enumerated(EnumType.STRING) 
    public Condition myCondition = Condition.BAD; 

    @Enumerated(EnumType.STRING) 
    @ElementCollection 
    public Set<Condition> conditions = new HashSet<Condition>(); 

    public enum Condition { 
     GOOD, FAIR, BAD, SOL 
    } 
} 

Wenn ich die folgende Abfrage mit einem Enum-Parameter ausführen, bekomme ich 0 (kein Fehler):

//Produces no results 
String queryString = "FROM MyEntity me WHERE :condition MEMBER OF me.conditions"; 
List<MyEntity> things = JPA.em().createQuery(queryString, MyEntity.class).setParameter("condition", Condition.BAD).getResultList(); 

Diese Abfrage erzeugt das folgende SQL:

select myentity0_.myentityid as myentity1_38_, myentity0_.mycondition as mycondit2_38_ 
from MyEntity myentity0_ 
where ? in (
    select conditions1_.conditions 
    from MyEntity_conditions conditions1_ 
    where myentity0_.myentityid=conditions1_.MyEntity_myEntityId) 

Wenn ich stattdessen ein Zeichenfolgenliteral verwende, erhalte ich Ergebnisse. Ich habe auch Ergebnisse, wenn ich die gleichen Parameter Strategie für Nicht-Sammlung Felder verwenden:

// Produces results 
queryString = "FROM MyEntity me WHERE 'BAD' MEMBER OF me.conditions"; 
things = JPA.em().createQuery(queryString, MyEntity.class).getResultList(); 

// Also produces results 
queryString = "FROM MyEntity me WHERE me.myCondition = :condition"; 
things = JPA.em().createQuery(queryString, MyEntity.class).setParameter("condition", Condition.BAD).getResultList(); 

//So does this 
String queryString = "from MyEntity me join me.conditions c where c = :condition"; 
List<MyEntity> things = JPA.em().createQuery(queryString, MyEntity.class).setParameter("condition", Condition.BAD).getResultList(); 

Diese Abfragen erzeugen die folgende SQL:

select myentity0_.myentityid as myentity1_38_, myentity0_.mycondition as mycondit2_38_ 
from MyEntity myentity0_ 
where 'BAD' in (
    select conditions1_.conditions 
    from MyEntity_conditions conditions1_ 
    where myentity0_.myentityid=conditions1_.MyEntity_myEntityId) 

select myentity0_.myentityid as myentity1_38_, myentity0_.mycondition as mycondit2_38_ 
from MyEntity myentity0_ 
where myentity0_.mycondition=? 

select myentity0_.myentityid as myentity1_38_, myentity0_.mycondition as mycondit2_38_ 
from MyEntity myentity0_ 
    inner join MyEntity_conditions conditions1_ on myentity0_.myentityid=conditions1_.MyEntity_myEntityId 
where conditions1_.conditions=? 

Bin ich in meiner Annahme falsch, dass Hibernate darauf achten sollte EnumType.STRING und EnumType.ORDINAL wenn Sie Parameter verwenden? Zumindest ist es inkonsequent. Das Ausfüllen von Parametern funktioniert beim Abfragen von Enum-Feldern, aber nicht beim Auflisten von Auflistungen. Was vermisse ich?

+0

Neben der Antwort, die Sie erhalten haben, können Sie sich immer helfen, indem es tatsächlich Debuggen ... an der SQL-Suche erzeugt ... und Blick auf die JPA-Spezifikation das sagt _Expressions, die einbettbare Typen auswerten, werden nicht in Auflistungsmember-Ausdrücken unterstützt –

+0

@Neil Stockton Was lässt Sie glauben, dass ich die Dinge nicht für mich selbst getestet habe?Sie haben hier in der Frage meinen Versuch, das Problem in einer vereinfachenden Einheit zu isolieren und zu identifizieren. Ich nehme an, ich hätte erwähnen können, dass das von der ersten und dritten JPQL-Abfrage generierte SQL dasselbe ist. Wie für die JPA - Spezifikation zählen Enum - Elemente als eingebettete Elemente? Ich hatte den Eindruck, dass Embeddables im Wesentlichen Unterklassen sind, die als einbettbar kommentiert sind. – Indigenuity

+0

Die Leute können nur kommentieren, was ihnen präsentiert wurde, und die meisten Leute hier präsentieren wenig bis gar kein Debugging, also ist das immer die Annahme. Was Ihr Problem anbelangt, kann ich es (nachdem ich in SELECT {alias} "make it valid JPQL" hinzugefügt habe) in dem JPA-Provider verwenden, den ich verwende (DataNucleus) und er erstellt ein SQL wie 'SELECT * FROM MYENTITY M INNER JOIN MYENTITY_CONDITIONS B0 ON M.ID = B0.MYENTITY_ID WHERE B0.CONDITIONS_ELEMENT = <'BAD'> ', also funktioniert das. Folglich scheint Ihr JPA-Provider das Problem zu sein, nicht Ihr Code –

Antwort

1

Sie haben eine falsche Zuordnung, daher sind die Ergebnisse unvorhersehbar.

Sie verpasst die @ElementCollection, nur @Enumerated auf einer Collection verwenden, es ist keine gültige Zuordnung.


Update

Es scheint, das Problem woanders ist.

Sie sollten das generierte SQL hinzufügen, damit wir weitere Informationen haben können.

ich auf ein äquivalentes Schema versucht haben, und die Abfrage läuft gut:

return em.createQuery("from DocumentType x where :family member of x.families", DocumentType.class) 
    .setParameter("family", DocumentFamily.GENERIC) 
    .setMaxResults(5) 
    .getResultList(); 

und auch

from DocumentType x where 'GENERIC' member of x.families 
from DocumentType x join x.families f where f = :family 
from DocumentType x join x.families f where f = 'GENERIC' 
from DocumentType x join x.families f where f = it.shape.edea2.jpa.enums.DocumentFamily.GENERIC 

gibt es zwei verschiedene generierten SQL-Abfragen:

select ... 
from ELEMENT_TYPE documentty0_ 
where documentty0_.DTYPE='DocumentType' 
    and ('GENERIC' in (
     select families1_.FAMILY 
     from DOCUMENT_TYPE_FAMILY families1_ 
     where documentty0_.ID=families1_.DOCUMENT_TYPE_ID)) 
limit 5 

select ... 
from ELEMENT_TYPE documentty0_ 
    inner join DOCUMENT_TYPE_FAMILY families1_ on documentty0_.ID=families1_.DOCUMENT_TYPE_ID 
where documentty0_.DTYPE='DocumentType' 
    and families1_.FAMILY='GENERIC' 
limit 5 

aber da ist etwas Seltsames:

from DocumentType x where it.shape.edea2.jpa.enums.DocumentFamily.GENERIC member of x.families 

wirft

org.hibernate.QueryException: Unrecognized Hibernate Type for handling query constant (it.shape.edea2.jpa.enums.DocumentFamily.GENERIC); expecting LiteralType implementation or AttributeConverter 

wich Version von Hibernate verwenden Sie?

Ich bin auf 5.2.2

+0

Mein Fehler: Wenn ich das Beispiel anführe, habe ich diese Annotation weggelassen. Dasselbe Verhalten tritt auch bei der Annotation auf Ich werde es tun Aktualisiere die Frage, um dies zu berücksichtigen. – Indigenuity

+0

siehe Aktualisierung. Welche Hibernate-Version? –

+0

Verwenden von 4.3.0, wie in Frage gestellt. Die Verwendung eines solchen Joins auf der Sammlung funktioniert mit dem Parameter, also muss er mit dem in Zusammenhang stehen, was @Neil Stockton über Sammlungen gesagt hat. Obwohl ich immer noch nicht weiß, warum ein Enum als Embeddable betrachtet wird. – Indigenuity

Verwandte Themen