2010-04-20 5 views
12

In Hibernate möchte ich diese JPQL/HQL-Abfrage auszuführen:Ist das möglich: JPA/Hibernate-Abfrage mit Listeneigenschaft in Ergebnis?

select new org.test.userDTO(u.id, u.name, u.securityRoles) 
FROM User u 
WHERE u.name = :name 

userDTO Klasse:

public class UserDTO { 
    private Integer id; 
    private String name; 
    private List<SecurityRole> securityRoles; 

    public UserDTO(Integer id, String name, List<SecurityRole> securityRoles) { 
    this.id = id; 
    this.name = name; 
    this.securityRoles = securityRoles; 
    } 

    ...getters and setters... 
} 

Benutzer Entity:

@Entity 
public class User { 

    @id 
    private Integer id; 

    private String name; 

    @ManyToMany 
    @JoinTable(name = "user_has_role", 
     joinColumns = { @JoinColumn(name = "user_id") }, 
     inverseJoinColumns = {@JoinColumn(name = "security_role_id") } 
) 
    private List<SecurityRole> securityRoles; 

    ...getters and setters... 
} 

Aber wenn Hibernate 3.5 (JPA 2) startet ich bekomme diesen Fehler:

org.hibernate.hql.ast.QuerySyntaxException: Unable to locate appropriate 
constructor on class [org.test.UserDTO] [SELECT NEW org.test.UserDTO (u.id, 
u.name, u.securityRoles) FROM nl.test.User u WHERE u.name = :name ] 

Ist eine Auswahl, die eine Liste enthält (u.securityRoles) als Ergebnis nicht möglich? Soll ich nur zwei separate Abfragen erstellen?

Antwort

10

Die Abfrage ohne NEW (einen skalaren Wert und eine Sammlung bewertet Wegausdruck Auswahl) ist nicht gültig, so dass ich eine NEW glaube nicht, dass das Hinzufügen Dinge funktionieren machen.

Für das Protokoll, das ist, was die JPA 2.0-Spezifikation im Abschnitt 4.8 SELECT-Klausel sagt:

The SELECT clause has the following syntax:

select_clause ::= SELECT [DISTINCT] select_item {, select_item}* 
select_item ::= select_expression [ [AS] result_variable] 
select_expression ::= 
     single_valued_path_expression | 
     scalar_expression | 
     aggregate_expression | 
     identification_variable | 
     OBJECT(identification_variable) | 
     constructor_expression 
constructor_expression ::= 
     NEW constructor_name (constructor_item {, constructor_item}*) 
constructor_item ::= 
     single_valued_path_expression | 
     scalar_expression | 
     aggregate_expression | 
     identification_variable 
aggregate_expression ::= 
     { AVG | MAX | MIN | SUM } ([DISTINCT] state_field_path_expression) | 
     COUNT ([DISTINCT] identification_variable | state_field_path_expression | 
        single_valued_object_path_expression) 
+2

Danke! Ich hätte es einfach in der JPA-Spezifikation nachschlagen sollen. Die u.securityRoles sind eindeutig kein 'single_valued_path_expression'. Also ich denke, das bedeutet, dass man separate Abfragen für das Abrufen von Sammlungen/Relationen durchführen muss (oder einen Join verwenden und die Sammlungen mit einer Schleife erstellen). – Kdeveloper

+1

@Kdeveloper Wenn Ihr Benutzer viele, viele Attribute hat, denke ich. Wenn nicht, wähle einfach den Benutzer und hole seine securityRoles. –

+0

@pascal thivent Und wenn die JPQL viele Benutzer zurückgibt, wird es schließlich zu einer Schleife führen, um die securityRoles jedes Benutzerrechts zu erhalten? – HopeKing

1

Ich glaube, dass Sie einen 0-Arg-Konstruktor in Ihrer Klasse UserDTO deklarieren müssen.

EDIT: Oder ein Konstruktor, der Integer anstelle von int als erstes Argument nimmt. Bei der Suche nach Konstruktoren, die Reflektion verwenden, behandelt Hibernate sie möglicherweise nicht als "kompatible" Typen.

Grundsätzlich würde ich auf den Unable to locate appropriate constructor on class [...UserDTO] Teil der Nachricht konzentrieren.

+0

Ich bin damit einverstanden, Es scheint, dass Hibernate keinen geeigneten Konstruktor finden kann. Aber warum? Wenn ich die SecurityRoles sowohl im Contructor als auch in der Abfrage lösche, funktioniert der Code ... – Kdeveloper

+0

Der Int zu Integer hat keinen Unterschied gemacht. Der Nullargumentkonstruktor wird nicht benötigt, weil die HQL explizit den benannten Konstruktor verwendet (oder zumindest normal) – Kdeveloper

-1

Ich denke, dass man so etwas versuchen soll:

select new org.test.userDTO(u.id, u.name, u.securityRoles) AS uDTO, 
    uDTO.setRoles(u.securityRoles) 
FROM User u 
WHERE u.name = :name 
+0

Ihr Vorschlag wird nicht kompiliert. – Maciej

Verwandte Themen