【问题标题】:Problems with making a query when using Enum in entity在实体中使用枚举时进行查询的问题
【发布时间】:2012-01-03 06:24:02
【问题描述】:

我在问题实体中有以下内容:

@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] 类型。在 org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:501)

我该如何解决这个问题?

【问题讨论】:

  • 您使用的是自定义枚举吗?您可以更新文档以显示 Status 枚举吗?

标签: java jpa jakarta-ee jpql


【解决方案1】:

我认为你应该使用你的(完全合格的)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 的值必须是常量表达式。
  • 你在说什么@Query注解?
  • 这个fully qualified 比我想象的更重要。
  • 附注:当枚举是实体的内部类时,它不起作用。如果这对您不起作用,请确保枚举是它自己的文件!
  • @evandongen 如果枚举是内部类,有什么解决方案吗?
【解决方案2】:

自最初发布以来的 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 表达式混合的内容转换为 Status 对象:

存储库:

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 将此表达式绑定到查询变量。

【讨论】:

  • 您在变量绑定中看不到它,因为该常量已被替换到查询字符串中。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2012-06-05
    • 2016-07-29
    • 1970-01-01
    • 2013-01-10
    相关资源
    最近更新 更多