Problems with making a query when using Enum in entity
JavaJpaJakarta EeJpqlJava Problem Overview
I have the following in a Question entity:
@NamedQuery(name = "Question.allApproved",
query = "SELECT q FROM Question q WHERE q.status = 'APPROVED'")
and
@Enumerated(EnumType.STRING)
private Status status;
// usual accessors
I am getting this exception:
> Exception Description: Error compiling the query
> [Question.countApproved: SELECT COUNT(q) FROM Question q WHERE q.status = 'APPROVED'
], line 1, column 47: invalid enum equal
> expression, cannot compare enum value of type
> [myCompnay.application.Status]
with a non enum value
> of type [java.lang.String]
. at
> org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:501)
How do I fix this?
Java Solutions
Solution 1 - Java
I think you should use your (fully qualified) Status
enum instead of literal value, so something like this: (assuming your Status
enum is in com.myexample
package)
@NamedQuery(name = "Question.allApproved",
query = "SELECT q
FROM Question q
WHERE q.status = com.myexample.Status.APPROVED").
Solution 2 - Java
4 years since the initial post, there are some developments. Using spring 4 and Hibernate 4 it's now possible to 'trick' Hibernate using a SpEL expression. For example:
The enum:
package com.mycompany.enums
public enum Status {
INITIAL, PENDING, REJECTED, APPROVED, SHIPPED, DELIVERED, COMPLETE;
}
Here's a wrapper class called 'Filter' which we'll pass to the repository filtering method.
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();
}
}
Finally, in the repository, we can now use the Filter class as the single parameter and make the query translate what appears to be a mixture of literals and SpEL expressions to a Status object:
The repository:
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);
}
This works perfectly, but for some odd reason I haven't figured out yet, if you enable SQL debugging in Hibernate and turn on the binder logging, you'll not be able to see Hibernate binding this expression to query variables.
Solution 3 - Java
Please use below property in application.properties logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE