109 votes

Problèmes liés à la création d'une requête lors de l'utilisation d'un Enum dans une entité

J'ai les éléments suivants dans une entité Question :

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

et

@Enumerated(EnumType.STRING)
private Status status;

// usual accessors

J'obtiens cette exception :

Description de l'exception : Erreur de compilation de la requête [Question.countApproved : SELECT COUNT(q) FROM Question q WHERE q.status = 'APPROVED' ], ligne 1, colonne 47 : expression invalide enum equal invalide, ne peut pas [myCompnay.application.Status] avec une valeur non enum de type [java.lang.String] . à org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:501)

Comment résoudre ce problème ?

226voto

Piotr Nowicki Points 7565

Je pense que vous devriez utiliser votre (pleinement qualifié) Status au lieu d'une valeur littérale, ce qui donne quelque chose comme ceci : (en supposant que votre Status est dans com.myexample paquet)

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

-5voto

Tom Silverman Points 31

4 ans après le post initial, il y a du nouveau. En utilisant Spring 4 et Hibernate 4, il est maintenant possible de "tromper" Hibernate en utilisant une expression SpEL. Par exemple :

L'énumération :

package com.mycompany.enums

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

Voici une classe enveloppante appelée "Filter" que nous transmettrons à la méthode de filtrage du référentiel.

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();
    }

 }

Enfin, dans le référentiel, nous pouvons maintenant utiliser la classe Filter comme paramètre unique et faire en sorte que la requête traduise ce qui semble être un mélange de littéraux et d'expressions SpEL en un objet Status :

Le dépôt :

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);
}

Cela fonctionne parfaitement, mais pour une raison étrange que je n'ai pas encore trouvée, si vous activez le débogage SQL dans Hibernate et que vous activez la journalisation du binder, vous ne pourrez pas voir Hibernate lier cette expression aux variables de la requête.

-11voto

Veuillez utiliser les propriétés suivantes dans application.properties

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X