有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Hibernategenerated列别名在使用查询时将别名断开为BeanResultTransformer

我试图实现的是在以下方式定义的查询上设置一个结果转换器:

String hqlQueryString = "select o.id as id, o.name as objectName from MyObject"; 
Class resultClass = MyObject.class;
Query query = session.createQuery(hqlQueryString).setResultTransformer(
        new new AliasToBeanResultTransformer(resultClass));
List result = query.list();

MyObject看起来像这样:

public class MyObject {
    private int id;
    private String objectName;

    public int getId() {
        return id;
    }
    public void setId(int value) {
        this.id = value;
    }

    public String getObjectName() {
        return objectName;
    }
    public void setobjectName(String value) {
        this.objectName = value;
    }
}

问题是,尽管我指定了idobjectName作为别名,但实际执行的查询使用不同的别名。这导致我的AliasToBeanResultTransformer无法构造MyObject,因为别名与属性名不匹配

是否可以通过编程方式获取hibernate生成的查询的别名(我可以将它们设置为alias to bean result Transformer)?我尝试使用query.getReturnAliases(),但它返回我在HQL中定义的别名,而不是Hibernate实际使用的别名

我可以在createQuery语句中显式指定别名吗?目前,我正在尝试不使用这个标准来工作,所以我希望有一种使用查询对象的方法,如果存在的话


更新

尽管上述问题对于标准HQL查询无效(请参阅注释),但在执行本机查询时仍然有效。具体地说,本机查询似乎将所有别名都视为小写字符串(尽管查询中可能引入了特定的大小写)。这会导致AliasToBeanResultTransformer在设置属性时失败,如果大小写很重要的话


共 (2) 个答案

  1. # 1 楼答案

    实际上不需要实现另一个AliasToBeanResultTransformer,您可以使用addScalar(String columnAlias, Type type)显式地为本机SQL的列别名:

    String nativeSQL = "select o.id as id, o.name as objectName from MyObject"; 
    List<MyObject> resultList = session.createSQLQuery(nativeSQL)
            .addScalar("id" ,StandardBasicTypes.INTEGER)
            .addScalar("objectName",StandardBasicTypes.STRING)
            .setResultTransformer(new AliasToBeanResultTransformer(MyObject.class))
            .list();
    

    然后,转换器将寻找一个MyObject类,并期望它具有设置器setId()setObjectName(),以便将返回的值填充到MyObject实例

  2. # 2 楼答案

    至于原生查询,没有简单的解决方案。我必须研究AliasToBeanResultTransformer类的实现,并在其中进行修复。我通过创建AliasToBeanResultTransformer类的副本解决了这个问题,并用以下方式修改了该类的private initialize方法:

    public class CaseInsensitiveAliasToBeanResultTransformer {
        private void initialize(String[] aliases) {
            this.aliases = new String[ aliases.length ];
            setters = new Setter[aliases.length];
            for ( int i = 0; i < aliases.length; i++ ) {
                String alias = aliases[i];
                if (alias != null) {
                    this.aliases[i] = alias;
                    setters[i] = CaseInsensitiveSetter.getSetter(resultClass, alias);
                }
            }
            isInitialized = true;
        }
    }
    

    这段代码的主要区别在于CaseInsensitiveSetter.getSetter(resultClass, alias)行,我在这里介绍了一个CaseInsensitiveSetter类,我将在下面描述。这个类实现了Setter接口,并允许使用不区分大小写的匹配检索类的Setter方法——因此这将允许我将小写查询别名绑定到结果类的正确成员。以下是自定义setter的代码(为了简洁起见,只显示了重要的行):

    public class CaseInsensitiveSetter {
    
        public static Setter getSetter(Class<?> theClass, String propertyName) {
    
            Setter setter;
    
            if (theClass == Object.class || theClass == null) {
                setter = null;
            } else {
                setter = doGetSetter(theClass, propertyName);
    
                if (setter != null) {
                    if (!ReflectHelper.isPublic(theClass, setter.getMethod())) {
                        setter.getMethod().setAccessible(true);
                    }
                } else {
                    setter = doGetSetter(theClass.getSuperclass(), propertyName);
                    if (setter == null) {
                        Class<?>[] interfaces = theClass.getInterfaces();
                        for (int i = 0; setter == null && i < interfaces.length; i++) {
                            setter = doGetSetter( interfaces[i], propertyName);
                        }
                    }
                }
                if (setter == null) {
                    throw new PropertyNotFoundException( 
                        "Could not find a setter for property " + 
                        propertyName + " in class " + theClass.getName());
                }
            }
            return setter;
        }
    
        // The actual work is done here
        private static Setter doGetSetter(Class<?> resultClass, String propertyName) {
    
            Method[] methods = resultClass.getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                // only carry on if the method has 1 parameter
                if ( methods[i].getParameterTypes().length == 1 ) {
                    String methodName = methods[i].getName();
    
                    if (methodName.startsWith("set")) {
                        String testStdMethod = methodName.substring(3);
                        if (testStdMethod.equalsIgnoreCase(propertyName)) {
                            Setter result = new CustomSetter(
                                resultClass, methods[i], propertyName);
                            return result;
                        }
                    }
                }
            }
            return null;
        }
    }
    

    其源代码基于Hibernate附带的BaseSetter类,但已更改为支持不区分大小写的匹配。不过,这个类以及Hibernate使用的原始类由于大量使用反射而缺乏性能

    另外,请记住,如果结果类包含不同的属性,并且这些属性的名称在不区分大小写的比较中是相等的,那么当前代码将只选取其中一个属性,并且它可能无法按预期工作