参数值与预期类型不匹配

问题描述 投票:0回答:4

我有一个带有状态列表的枚举(例如)

enum State
{
   UP,
   DOWN,
   RETRY
};

我的数据库中的列是枚举类型。当我尝试通过使用

setParameter("keyword", State.RETRY);
设置查询中的参数来执行 Hibernate 查询时,我收到以下错误:

参数值[RETRY]与预期类型不匹配 [包.名称.状态(不适用)]

在我的域的 Glassfish 4.1 server.log 中。我正在使用 Hibernate 4.3.6。

在查看 Hibernate 的源代码时,我发现错误是由于

org.hibernate.jpa.spi.BaseQueryImpl 中的 958-960 行

 发生的:

private static boolean isValidBindValue(Class expectedType, Object value, TemporalType temporalType) { if ( expectedType.isInstance( value ) ) { return true; } ... return false; }

isValidBindValue

 返回 false,因此我收到了消息。

由于这一行,它打印出

String

 等价于 
enum
 值:

String.format("Parameter value [%s] did not match expected type [%s (%s)]", bind, parameterType.getName(), extractName( temporalType ) )

通过调用代表

bind

toString
 上的 
Object
 方法,将 
enum State.RETRY
 对象隐式转换为 String 值。

那么我如何才能让 Hibernate 相信

State.RETRY

State
 的实例?

看起来 Hibernate 更新到了 JPA 2.1 规范,该规范在 2013 年 4 月的提交中更加严格:

https://github.com/hibernate/hibernate-orm/commit/84520cd6e36e9207c41528cf9311cae905a86425

实体注释如下:

@Basic(optional = false) @Column(name = "state") @Enumerated(EnumType.String) private State state;

编辑:

我的

RetryState

 枚举由 
EarLibClassLoader
 加载。而 
Query
 由 URLClassLoader 加载,而 
EntityManager
 由不同的类加载器加载。

java hibernate classloader glassfish-4
4个回答
6
投票
我想主要问题是您尝试在数据库端使用枚举数据类型。不建议这样做,因为它通常需要专有的枚举类型,而 JPA 实现(例如 Hibernate)可能无法很好地支持该类型。有关一些详细信息,请参阅类似问题的

此答案

进一步,带有注释

@Enumerated(EnumType.String)

您是说您明确希望将该值保存为

作为字符串在数据库中。如果真正的列类型是某种枚举,我预计这会失败。也许 Hibernate 代码更改试图通过强制您使用 varcharinteger 列来防止这些问题。

可能的解决方案:

A)

使用带

@Enumerated(EnumType.String)

 的 varchar 列或带 
@Enumerated
 的 int 列

B)

您可以尝试通过注释指定枚举列

@Basic(optional = false) @Column(name = "state", columnDefinition = "enum('UP','DOWN','RETRY')") @Enumerated(EnumType.String) private State state;

C)

您可以尝试通过 hibernate XML 映射文件指定您的枚举类:

<property name="type" column="type" not-null="true"> <type name="org.hibernate.type.EnumType"> <param name="enumClass">package.name.State</param> <param name="type">12</param> <!-- 12 is java.sql.Types.VARCHAR --> </type> </property>

另请参阅:

  • JPA 枚举类型映射。最好的方法
  • Hibernate 中的枚举,持久化为枚举
  • MySQL Enum 性能优势?

1
投票
通过将带有 JPA 注释的类和枚举类放入

domain-dir/lib/applib 目录来修复此问题。您必须将这些类放入 domain-dir/lib/applib 目录中的 JAR 中,然后使用 --libraries jar1,jar2,etc

 在 asadmin 的部署命令上指定 jar。列出多个 JAR 文件时,请勿在逗号后添加空格。

此外,我有一个具有 EJB 远程接口的通用 JAR,因此我必须将 JPA 类分解为一个新 JAR,并将它们也放在我的

applibs 目录中。然后,我将带有 EJB 远程接口的 JAR 放入我的 EAR\lib 目录中。

lib/applibs目录中的JAR由URLClassLoader加载。 EAR\lib 中的 JAR 由 EARLibClassLoader 加载。


0
投票
我在一个项目上遇到了同样的问题,但经过几次尝试后,创建一个表来替换我的枚举更有意义。然而,使用 Jackson 似乎可以工作


0
投票
在我的情况下,我使用 criteriaBuilder 针对带有注释的列创建“等于”查询:@Enumerated(EnumType.STRING)

我在构建查询条件之前更新了逻辑,以便将我搜索的字符串转换为其相对枚举值。

我可以访问列的类路径,并使用反射来转换值,然后再将其放入 criteriaBuilder。

try { Class<?> enumClass = Class.forName(classPath); Method valueOfMethod = enumClass.getMethod("valueOf", String.class); return valueOfMethod.invoke(null, value); } catch ( ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e ) { throw new IllegalArgumentException( "Enumerated column does not currently support search: " + classPath ); }
最后

cond = cb.and(cond, cb.equal(equalPath, enumValueFromAbove));
    
© www.soinside.com 2019 - 2024. All rights reserved.