5

「クエリで取得タイプを指定する」という行に沿って何かを言う前に読んでください。それは私が求めているものではありません。

完全なオブジェクトグラフ (オブジェクト + そのすべての子とそのすべての子など) を熱心に読み込む方法を探しています。

ロードされるすべてのプロパティを列挙したくありません。私は実行時までそれらを知りません。

N+1 クエリは問題になりません。しかし、この魔法のような操作の最後に、グラフに単一のプロキシまたは遅延コレクションを残したくありません。

すべてのプロパティを反射的かつ再帰的に調べるコードを少し書くことができるはずです。しかし、コレクションはこれを扱いにくく複雑にします。

そういう意味でDozerを勧めている人もいますが、それは少しやり過ぎに思えるので、最後の手段として取っておきたいと思います。

4

2 に答える 2

0

簡単な解決策はlazy="false"、すべてのコレクション(1:NおよびN:M)と関連付け(1:1)を指定することです。

これにより、トランザクションごとにグラフ全体がメモリに読み込まれます。したがって、これが正しく機能するためには、最大で1つのトランザクションが必要です。そうしないと、パフォーマンスが大幅に低下します。

これはあなたが望むことをするでしょうが、コストが高すぎるかもしれません。「フェッチプロファイル」を使用して実行時にさまざまな戦略を選択できますが、Hibernateはオブジェクトを要求するときに常にコピーを提供するため、毎回グラフをコピーする必要があります。

私にとって、これはHibernateがタスクにとって単に間違ったツールであるように思えます。Hibernateを使用したエンティティのマッピングは快適ですが、Hibernateがモデルとビジネスコードにリークするという犠牲が伴います。Hibernateによって課せられた制約が請求に合わない場合は、他の場所を探す必要があります。

Recordたぶん、完全に肉付けされたJava Beanの代わりに、型を使用して生きることができます。もしそうなら、あなたは「アクティブレコード」パターンを実装するjOOQまたはフレームワークを見ることができます。

Beanが必要で、特定の種類のデータベースに制限されていない場合は、 db4oなどのOOデータベースを試してください。

最後に、なぜSQLを使用するのですか?オブジェクトグラフ全体が常に必要な場合は、ファイルにシリアル化して起動時にロードしてみませんか?または、メモリ常駐データベースを使用します。

于 2013-01-07T12:54:33.023 に答える
0

私はかつてそれに似たものが必要でした、そしてそれを解決するためにReflectionを使わなければなりませんでした。私の場合、hqlを使用してレコードを取得していました。また、これは遅延読み込みとして定義されているレコードを積極的に読み込むために作成したアプローチであるため、最初のメソッドをFetchType.LAZYプロパティを検索せず、常にフェッチするように調整することをお勧めします。

私が構築したメソッドの1つは、遅延フェッチを「準備」します。基本的に2つのアプローチ:@ManyToOneのhqlで「leftjoin fetch」を使用する方法と、@OneToManyおよび@ManyToManyのhibernate.initialize()を使用する方法です。

したがって、この最初のメソッドは、hqlに必要な「leftjohn fetch」を含む文字列を返し、クエリの実行後にHibernate.initialize()によって呼び出される必要があるnToManyフィールドのリストも作成します。

private String buildLazyFetch(Class<? extends GenericEntity> entityClass, List<String> nToManyFields) {
    String lazyFetches = new String();
    lazyFetches += " fetch all properties ";
    // iterate through all fields looking for lazy loaded relationships
    for (Field f : entityClass.getDeclaredFields()) {
        ManyToOne manyToOne = f.getAnnotation(ManyToOne.class);
        if (manyToOne != null) {
            if (manyToOne.fetch().equals(FetchType.LAZY)) {
                lazyFetches += " left join fetch t." + f.getName() + " ";
            }
        }
        OneToMany oneToMany = f.getAnnotation(OneToMany.class);
        if (oneToMany != null) {
            if (oneToMany.fetch().equals(FetchType.LAZY)) {
                nToManyFields.add(f.getName());
            }
        }
        ManyToMany manyToMany = f.getAnnotation(ManyToMany.class);
        if (manyToMany != null) {
            if (manyToMany.fetch().equals(FetchType.LAZY)) {
                nToManyFields.add(f.getName());
            }
        }
    }
    return lazyFetches;
}

hqlが実行された後は、次のように呼び出します。

private void lazyFetchNToMany (List<String> nToManyFields, GenericEntity entity) {
    for (String field : nToManyFields) {
        try {
            Hibernate.initialize(BeanUtils.getProperty(entity, field));
        } catch (HibernateException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

これはあなたが期待したものとは正確には一致しないことを理解していますが、希望する解決策が見つからない場合に役立つ可能性があります

于 2013-01-07T13:24:56.710 に答える