使用实体中的枚举类型进行查询时出现问题

112

我有一个Question实体,其中包含以下内容:

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

并且

@Enumerated(EnumType.STRING)
private Status status;

// usual accessors

我遇到了这个异常:

异常描述:编译查询错误 [Question.countApproved: SELECT COUNT(q) FROM Question q WHERE q.status = 'APPROVED'],第1行,第47列:无效的枚举等式表达式,无法将类型为[myCompnay.application.Status]的枚举值与类型为[java.lang.String]的非枚举值进行比较。 at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:501)

我该如何解决这个问题?


你是否使用自定义枚举?你能否更新文档以显示状态枚举? - Gonzalo Garcia Lasurtegui
3个回答

236

我认为你应该使用你的(完整限定)Status枚举代替字面值,所以应该像这样做:(假设你的Status枚举在com.myexample包中)

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

JPA2 中的 @Query 呢?它会报错:注解属性 Query.value 的值必须是一个常量表达式。 - Stephane
2
你在说哪个 @Query 注解? - Piotr Nowicki
4
这个“完全合格”的资格比我想象的更重要。 - alexander
17
附带一提:当枚举类是实体类的内部类时,它不起作用。如果这对你不起作用,请确保枚举类是单独的文件! - evandongen
1
@evandongen 如果枚举是内部类,有什么解决方案吗? - Raja aar
显示剩余6条评论

-4

距离最初的帖子已经过去了4年,现在有一些进展。使用Spring 4和Hibernate 4,现在可以使用SpEL表达式“欺骗”Hibernate。例如:

枚举:

package com.mycompany.enums

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

这里有一个包装类叫做“Filter”,我们将把它传递给存储库过滤方法。
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();
    }

 }

最后,在存储库中,我们现在可以使用Filter类作为单个参数,并将查询转换为看起来是文字和SpEL表达式混合的状态对象:

存储库:

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

这个工作得很完美,但是由于某些奇怪的原因我还没有弄清楚,如果你在Hibernate中启用了SQL调试并打开绑定器日志记录,你将无法看到Hibernate将这个表达式绑定到查询变量。


你在变量绑定中看不到它,因为常量已经被替换到查询字符串中了。 - AbuNassar

-11
请在application.properties文件中使用以下属性:
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接