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

問題は、エイリアスを指定したにもかかわらず、id実行objectNameされる実際のクエリが異なるエイリアスを使用することです。これにより、エイリアスがプロパティ名と一致しないため、AliasToBeanResultTransformer構築に失敗します。MyObject

プログラムでHibernateによって生成されたクエリのエイリアスを取得することは可能ですか(Bean結果トランスフォーマーのエイリアスに設定できます)?使用してみquery.getReturnAliases()ましたが、Hibernateが実際に使用するエイリアスではなく、HQLで定義したエイリアスが返されます。

createQueryステートメントでエイリアスを明示的に指定できますか?現在、これが機能するための基準を使用しないようにしています。そのため、クエリオブジェクトが存在する場合は、それを使用するアプローチをいただければ幸いです。


アップデート

上記の問題は、標準のHQLクエリ(コメントを参照)では無効ですが、ネイティブクエリを実行する場合は有効です。具体的には、ネイティブクエリはすべてのエイリアスを小文字の文字列として扱うように見えました(クエリで導入された可能性のある特定の大文字化にもかかわらず)。これにより、AliasToBeanResultTransformer大文字と小文字が重要な場合に、プロパティを設定するときにが失敗します。

4

2 に答える 2

7

実際には別のものを実装する必要はありません 。addScalar(String columnAlias、Type type)を使用して、ネイティブSQLの列を明示的にエイリアスするAliasToBeanResultTransformerことができます。

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が使用する元のクラスは、リフレクションを多用するため、パフォーマンスが不足しています。

また、結果クラスに大文字と小文字を区別しない比較で等しい名前の異なるプロパティが含まれている場合、それらの1つだけが現在のコードによって選択され、期待どおりに機能しない可能性があることに注意してください。

于 2012-04-05T15:55:06.353 に答える