Problemas al hacer una consulta al usar Enum en la entidad

3 minutos de lectura

avatar de usuario
lucaslucas

Tengo lo siguiente en una entidad Pregunta:

@NamedQuery(name = "Question.allApproved",
    query = "SELECT q FROM Question q WHERE q.status="APPROVED"")

y

@Enumerated(EnumType.STRING)
private Status status;

// usual accessors

Estoy recibiendo esta excepción:

Descripción de la excepción: error al compilar la consulta
[Question.countApproved: SELECT COUNT(q) FROM Question q WHERE q.status="APPROVED"]línea 1, columna 47: expresión igual de enumeración no válida, no se puede comparar el valor de enumeración del tipo
[myCompnay.application.Status] con un valor no enumerado de tipo [java.lang.String]. en org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:501)

¿Cómo puedo solucionar esto?

  • ¿Está utilizando una enumeración personalizada? ¿Puede actualizar el documento para mostrar la enumeración de estado?

    – Gonzalo García Lasurtegui

    21 de noviembre de 2011 a las 19:22

Creo que deberías usar tu (completamente calificado) Status enum en lugar de valor literal, por lo que algo como esto: (suponiendo que su Status la enumeración está en com.myexample paquete)

@NamedQuery(name = "Question.allApproved", 
            query = "SELECT q 
                     FROM Question q 
                     WHERE q.status = com.myexample.Status.APPROVED").

  • ¿Qué pasa con un @Query regular de JPA2? Se queja con: El valor del atributo de anotación Query.value debe ser una expresión constante.

    – Stéphane

    21 de septiembre de 2014 a las 10:23

  • Qué @Query anotación de la que hablas?

    –Piotr Nowicki

    21 de septiembre de 2014 a las 12:31

  • Este fully qualified es más importante como pensé que podría ser.

    – Alejandro

    12 de agosto de 2015 a las 16:13

  • En una nota al margen: no funcionó cuando la enumeración era una clase interna de la entidad. Si esto no funciona para usted, ¡asegúrese de que la enumeración sea su propio archivo!

    – evandongen

    10 de octubre de 2019 a las 6:57

  • @evandongen ¿alguna solución si la enumeración es una clase interna?

    – Raja aar

    5 de enero de 2021 a las 13:56

4 años desde el post inicial, hay algunos avances. Usando spring 4 e Hibernate 4, ahora es posible ‘engañar’ a Hibernate usando una expresión SpEL. Por ejemplo:

La enumeración:

package com.mycompany.enums

public enum Status {
    INITIAL, PENDING, REJECTED, APPROVED, SHIPPED, DELIVERED, COMPLETE;
}

Aquí hay una clase contenedora llamada ‘Filtro’ que pasaremos al método de filtrado del repositorio.

package com.mycompany.enums

public class Filter implements Serializable {

    /** The id of the filtered item */
    private Integer id;
    /** The status of the filtered item */
    private Status status;
    // more filter criteria here...

    // getters, setters, equals(), hashCode() - omitted for brevity

    /**
     * Returns the name of the status constant or null if the status is null. This is used in the repositories to filter
     * queries by the status using a the SPEL (T) expression, taking advantage of the status qualified name. For example:
     * {@code :#{T(com.mycompany.enums.Status).#filter.statusName}}
     *
     * @return the status constant name or null if the status is null
     */
    public String getStatusName() {
        return null == status ? status : status.name();
    }

 }

Finalmente, en el repositorio, ahora podemos usar la clase Filter como único parámetro y hacer que la consulta traduzca lo que parece ser una mezcla de literales y expresiones SpEL a un objeto Status:

El repositorio:

package com.mycompany.repository

@Repository
public interface OrderRepository extends CrudRepository<Order, Integer> {

    @Query("SELECT o from Order o "
            + "WHERE o.id = COALESCE(:#{#filter.id},o.id) "
            + "AND o.status = COALESCE(:#{T(com.mycompany.enums.Status).#filter.statusName},o.status)")
    public List<Order> getFilteredOrders(@Param(value = "filter") Filter filter);
}

Esto funciona perfectamente, pero por alguna extraña razón que aún no he descubierto, si habilita la depuración de SQL en Hibernate y activa el registro del enlazador, no podrá ver que Hibernate vincule esta expresión a las variables de consulta.

  • No lo ve entre los enlaces de variables porque la constante ya se sustituyó en la cadena de consulta.

    – Abu Nassar

    18 de diciembre de 2018 a las 16:33

avatar de usuario
choudhary Santosh

Utilice la siguiente propiedad en application.properties

logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

¿Ha sido útil esta solución?