2

我想要实现的是在以下列方式定义的查询上设置结果转换器:

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作为我的别名,但正在执行的实际查询使用不同的别名。这会导致 myAliasToBeanResultTransformer无法构造MyObject,因为别名与属性名称不匹配。

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

我可以在createQuery语句中明确指定别名吗?目前我试图不使用标准来实现这一点,所以我很欣赏一种使用查询对象的方法,如果存在的话。


更新

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

4

2 回答 2

7

其实不需要实现另一个 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 实例中

于 2012-04-05T20:07:19.340 回答
1

至于本机查询,没有涉及简单的解决方案。我不得不研究AliasToBeanResultTransformer该类的实现并在那里进行修复。我通过创建类的副本解决了这个问题,AliasToBeanResultTransformer并通过以下方式修改了该类的私有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 方法 - 因此这将允许我将小写查询别名绑定到我的结果类的正确成员。这是自定义设置器的代码(为简洁起见,仅显示重要的行):

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;
    }
}

其来源是基于BaseSetterHibernate 自带的类,但改为支持不区分大小写的匹配。尽管如此,这个类,以及 Hibernate 使用的原始类,由于大量使用反射而缺乏性能。

另外,请记住,如果结果类包含名称在不区分大小写的比较中相同的不同属性,则当前代码只会选择其中一个,并且可能无法按预期工作。

于 2012-04-05T15:55:06.353 回答