Hibernate 在 Enum Compare 上抛出 Query SemanticException:无法解释路径表达式

Sle*_*vin 5 spring hibernate jpa

有谁知道为什么 Hibernate 会抛出这个错误?

org.hibernate.query.SemanticException: Could not interpret path expression 'com.example.entity.security.AccountStatus.Description.ACTIVE'
at org.hibernate.query.hql.internal.BasicDotIdentifierConsumer$BaseLocalSequencePart.resolvePathPart(BasicDotIdentifierConsumer.java:256) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
at org.hibernate.query.hql.internal.BasicDotIdentifierConsumer.consumeIdentifier(BasicDotIdentifierConsumer.java:91) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitSimplePath(SemanticQueryBuilder.java:4808) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitIndexedPathAccessFragment(SemanticQueryBuilder.java:4755) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitGeneralPathFragment(SemanticQueryBuilder.java:4724) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitGeneralPathExpression(SemanticQueryBuilder.java:1423) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
at org.hibernate.grammars.hql.HqlParser$GeneralPathExpressionContext.accept(HqlParser.java:6963) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
Run Code Online (Sandbox Code Playgroud)

据报道,具有错误查询的存储库如下所示:

org.hibernate.query.SemanticException: Could not interpret path expression 'com.example.entity.security.AccountStatus.Description.ACTIVE'
at org.hibernate.query.hql.internal.BasicDotIdentifierConsumer$BaseLocalSequencePart.resolvePathPart(BasicDotIdentifierConsumer.java:256) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
at org.hibernate.query.hql.internal.BasicDotIdentifierConsumer.consumeIdentifier(BasicDotIdentifierConsumer.java:91) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitSimplePath(SemanticQueryBuilder.java:4808) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitIndexedPathAccessFragment(SemanticQueryBuilder.java:4755) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitGeneralPathFragment(SemanticQueryBuilder.java:4724) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
at org.hibernate.query.hql.internal.SemanticQueryBuilder.visitGeneralPathExpression(SemanticQueryBuilder.java:1423) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
at org.hibernate.grammars.hql.HqlParser$GeneralPathExpressionContext.accept(HqlParser.java:6963) ~[hibernate-core-6.1.6.Final.jar:6.1.6.Final]
Run Code Online (Sandbox Code Playgroud)

Description实体内部的enumAccountStatus看起来像这样:

@Repository
public interface UserAccountRepository extends JpaRepository<UserAccount, Long> {

    @EntityGraph(type = EntityGraph.EntityGraphType.FETCH, attributePaths = {
            "accountStatus"
    })
    @Query("""
            SELECT user
            FROM UserAccount user
            WHERE user.userId = ?1
            AND user.accountStatus.description = com.example.entity.security.AccountStatus.Description.ACTIVE
            """)
    Optional<UserAccount> findActiveByUserId(Long userId);
}
Run Code Online (Sandbox Code Playgroud)

奇怪的是,与字符串的直接比较是有效的。所以这个查询不会引起任何问题:

@Entity
public class AccountStatus {

    //...

    @JsonIgnoreType
    public enum Description {
        ACTIVE, INACTIVE, DISABLED, BANNED;

        private static Map<String, Description> descriptionByName;

        public static Description getByName(String name) {
            if (descriptionByName == null) {
                descriptionByName = Arrays.stream(values())
                        .collect(Collectors.toMap(Description::name, d -> d));
            }
            return descriptionByName.get(name);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

只有与相应的枚举值进行比较才会引发错误。 有谁知道这可能是什么?

非常感谢您的帮助

Chr*_*kov 5

Java 中的内部类由 分隔$,而不是,这就是为什么如果您想使用完全限定名称,则.必须使用。com.example.entity.security.AccountStatus$Description.ACTIVE

我建议您简单地使用简单名称 ( ACTIVE),或者如果可能的话,使用简单限定名称 ( Description.ACTIVE)。

  • 在 Hibernate 6 中,我们引入了对简写语法的支持。对于 Hibernate 5,我相信您必须在 HQL 中使用 FQN,但正如您所想到的,也可以与 JDBC 表示形式(即字符串枚举名称或序数)进行比较。 (2认同)