プロパティがすべてレイジーにロードされているHibernateオブジェクトがあります。これらのプロパティのほとんどは、他のHibernateオブジェクトまたはPersistentSetです。
ここで、Hibernateにこれらのプロパティを一度だけ熱心にロードするように強制したいと思います。
もちろん、これらの各プロパティをobject.getSite().size()
で「タッチ」することもできますが、目標を達成する別の方法があるかもしれません。
ドキュメントはそれを次のようにしています:
HQLの
fetch all properties
を使用して、プロパティの通常の熱心なフェッチを強制できます。
これは古い質問ですが、静的メソッドHibernate.initialize
についても指摘したいと思います。
使用例:
Person p = sess.createCriteria(Person.class, id);
Hibernate.initialize(p.getChildren());
これで、セッションが閉じられた後でも使用できるように子が初期化されます。
Dozer このタイプの場合はうまく機能します-オブジェクトを同じクラスの別のインスタンスにマップするようにDozerに依頼すると、Dozerは現在のオブジェクトから到達可能なすべてのオブジェクトにアクセスします。
詳細については、 同様の質問に対するこの回答 および 別の関連する質問に対する私の回答 を参照してください。
私にとってこれはうまくいきます:
Person p = (Parent) sess.get(Person.class, id);
Hibernate.initialize(p.getChildren());
これではなく:
Person p = sess.createCriteria(Person.class, id);
Hibernate.initialize(p.getChildren());
つの方法
1.左結合の子を持つHQL
2.createCriteria後のSetFetchMode
3.Hibernate.initialize
初期化する必要のあるすべてのアイテムを往復するため、これは低速ですが、作業は完了します。
private void RecursiveInitialize(object o,IList completed)
{
if (completed == null) throw new ArgumentNullException("completed");
if (o == null) return;
if (completed.Contains(o)) return;
NHibernateUtil.Initialize(o);
completed.Add(o);
var type = NHibernateUtil.GetClass(o);
if (type.IsSealed) return;
foreach (var prop in type.GetProperties())
{
if (prop.PropertyType.IsArray)
{
var result = prop.GetValue(o, null) as IEnumerable;
if (result == null) return;
foreach (var item in result)
{
RecursiveInitialize(item, completed);
}
}
else if (prop.PropertyType.GetGenericArguments().Length > 0)
{
var result = prop.GetValue(o, null) as IEnumerable;
if (result == null) return;
foreach (var item in result)
{
RecursiveInitialize(item, completed);
}
}
else
{
var value = prop.GetValue(o, null);
RecursiveInitialize(value, completed);
}
}
}