Enum字段类型的Hibernate SQL转换失败

时间:2012-03-09 11:31:29

标签: sql hibernate enums hql transformation

我正在使用SQL查询,然后使用Hibernates的Transformers.aliasToBean()转换结果。 我的查询中的一列是枚举。这种转变在某种程度上失败了。我该怎么办?我应该使用哪种数据类型?我想要超过1个字符将结果转换为我的枚举类型。

这是我的查询/代码的简化版本的样子( b 是表格配置文件中的枚举):

session.createSQLQuery("select a, b from profiles").setResultTransformer(Transformers.aliasToBean(Profile.class))
                    .list();

例外:expected type: Foo.ProfileStateEnum, actual value: java.lang.Character

3 个答案:

答案 0 :(得分:12)

假设与b列对应的java枚举类型是Foo.ProfileStateEnum,则以下代码段应该适合您。 (我用Hibernate 4.1.6测试过)

import java.util.Properties;
import org.hibernate.type.Type;
import org.hibernate.type.IntegerType;
import org.hibernate.internal.TypeLocatorImpl.TypeLocatorImpl;
import org.hibernate.type.TypeResolver.TypeResolver;
import org.hibernate.type.EnumType;

Properties params = new Properties();
params.put("enumClass", "Foo.ProfileStateEnum");
params.put("type", "12"); /*type 12 instructs to use the String representation of enum value*/
/*If you are using Hibernate 5.x then try:
params.put("useNamed", true);*/
Type myEnumType = new TypeLocatorImpl(new TypeResolver()).custom(EnumType.class, params);

List<Profile> profileList= getSession().createSQLQuery("select a as ID, b from profiles")
            .addScalar("ID", IntegerType.INSTANCE)
            .addScalar("b", myEnumType )
            .setResultTransformer(Transformers.aliasToBean(Profile.class))
            .list();

答案 1 :(得分:1)

我找到了两种方法来实现它。

  1. org.hibernate.type.CustomTypeorg.hibernate.type.EnumType一起使用(放置EnumType.NAMEDEnumType.TYPE,请参见EnumType#interpretParameters)。如下所示:

    Properties parameters = new Properties();
    parameters.put(EnumType.ENUM, MyEnum.class.getName());
    // boolean or string type of true/false; declare database type
    parameters.put(EnumType.NAMED, true);
    // string only; declare database type
    parameters.put(EnumType.TYPE, String.valueOf(Types.VARCHAR));
    EnumType<MyEnum> enumType = new EnumType<>();
    enumType.setTypeConfiguration(new TypeConfiguration());
    enumType.setParameterValues(parameters);
    CustomType customEnumType = new CustomType(enumType);
    
  2. 另一种简单的方法。将org.hibernate.type.StandardBasicTypeTemplateorg.hibernate.type.descriptor.sql.*TypeDescriptor一起使用。如下所示:

    StandardBasicTypeTemplate<MyEnum> enumType =
            new StandardBasicTypeTemplate<>(VarcharTypeDescriptor.INSTANCE,
                    new EnumJavaTypeDescriptor<>(MyEnum.class));
    

答案 2 :(得分:0)

让我们看看你为什么会遇到这个例外。

从问题中可以明显看出,您已在模型类中使用了{em>&#39; b&#39; 字段的@Enumerated(EnumType.STRING)注释。因此,该字段是您的模型类的枚举和数据库的 varchar 。本机SQL不关心您的模型类,并返回数据库表中的内容。因此,在您的情况下,您使用的SQLQuery将为&#39; b&#39; 而不是String类型返回ProfileStateEnum。但是,Profile类中&#39; b&#39; 的setter方法采用ProfileStateEnum类型参数。

因此你得到异常&#34;期望类型:Foo.ProfileStateEnum,实际值:java.lang.Character&#34;

您可以使用别名来解决问题。

我的建议是,使用您想要的任何名称为您的列添加别名,并在模型/ dto中为该别名创建一个setter方法。

例如,允许您将列别名为&#39; enumStr&#39;。

然后您的查询将如下所示:&#34; 从个人资料中选择a,b作为enumStr &#34;

现在,在Profile类中为该别名创建一个setter方法。

(假设枚举ProfileStateEnum可以包含STATE1STATE2两个值中的任何一个

public void setEnumStr(String str){
    /*Convert the string to enum and set the field 'b'*/
    if(str.equals(ProfileStateEnum.STATE1.toString())){
        b = ProfileStateEnum.STATE1;
    } else {
        b = ProfileStateEnum.STATE2;
    }
}

现在在转换时,将调用别名setEnumStr(String)的setter而不是字段setB(ProfileStateEnum)的setter,字符串将被转换并保存到您想要的类型,没有任何例外。

我是Hibernate的初学者,解决方案对我有用。我正在使用PostgreSQL。但我相信它也适用于其他数据库。