2010-04-20 14 views
12

En hibernación que desea ejecutar este JPQL/HQL consulta: clase¿Es esto posible: consulta JPA/Hibernate con propiedad de lista en el resultado?

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

userDTO: Entidad

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

usuario:

@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... 
} 

Pero cuando Hibernate 3.5 (APP 2) comienza me sale este error:

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 ] 

¿No es posible seleccionar un listado que incluya una lista (u.securityRoles) como resultado? ¿Debo simplemente crear 2 consultas separadas?

Respuesta

10

La consulta sin la NEW (selección de un valor escalar y una expresión de ruta de recogida de valor) no es válida, así que no creo que la adición de un NEW hará que las cosas funcionen.

Para el registro, esto es lo que la especificación JPA 2.0 dice en la sección 4.8 Cláusula SELECT:

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

¡Gracias! Debería haberlo buscado en la especificación de JPA. Claramente, u.securityRoles no es una 'single_valued_path_expression'. Así que supongo que esto significa que uno tiene que hacer consultas separadas para recuperar colecciones/relaciones (o usar una unión y crear las colecciones con un bucle). – Kdeveloper

+1

@ Kdeveloper Si su usuario tiene muchos atributos, supongo que sí. Si no, simplemente selecciona al usuario y busca sus securityRoles. –

+0

@pascal thivent Y si el JPQL devuelve muchos usuarios, eventualmente resultará en un bucle para recuperar los securityRoles de cada usuario ¿no? – HopeKing

1

Creo que necesita declarar un constructor 0-arg en su clase UserDTO.

EDIT: O un constructor que toma Integer en lugar de int como primer argumento. Al buscar constructores utilizando la reflexión, es posible que Hibernate no los trate como tipos "compatibles".

Básicamente, me centraría en la parte Unable to locate appropriate constructor on class [...UserDTO] del mensaje.

+0

Estoy de acuerdo, parece que Hibernate no puede encontrar un constructor apropiado. ¿Pero por qué? Si elimino las securityRoles en el contructor y consulta el código funciona ... – Kdeveloper

+0

El int a Integer, no hizo la diferencia. El constructor de argumento cero no es necesario, porque el HQL utiliza explícitamente el constructor nombrado (o al menos lo hace normalmente) – Kdeveloper

-1

pienso que usted debe intentar algo como:

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

Su sugerencia no se compila. – Maciej

Cuestiones relacionadas