2012-01-31 5 views
2

アドホックIDのリストに基づいて多数のエンティティを効率的にロードする必要があります。残念ながら、Restrictions.In(Projections.Id(), ids)のクエリーを実行するときに第2レベルのキャッシュが最初にチェックされるようには見えません。キャッシュをサポートする複数のアドホックNHibernateエンティティを効率的にロードする

ISession.Loadと似たようなものを探しています(1つではなく)IDのコレクションをとり、1番目または2番目のレベルのキャッシュで見つからないエンティティに対してINクエリを実行します。このようなものが存在しない場合、リフレクションに頼らずに2つのキャッシュを手動でチェックする最も簡単な方法は何ですか?

+0

たSession.loadの何が問題になっている:

static IList<T> LoadAll<T>(this ISession session, params object[] ids) where T : class { var results = new T[ids.Length]; var uncachedIds = new Dictionary<object, int>(); var helper = new LoadHelper(); for (var i = 0; i < ids.Length; i++) { var id = ids[i]; var evt = new LoadEvent(id, typeof (T).FullName, false, (SessionImpl) session); helper.OnLoad(evt, LoadEventListener.Get); var entity = (T) evt.Result; if (entity != null) { results[i] = entity; } else { uncachedIds.Add(id, i); } } if (uncachedIds.Count > 0) { var entities = session.CreateCriteria<T>() .Add(Restrictions.In(Projections.Id(), uncachedIds.Keys)) .List<T>(); foreach (var entity in entities) { var id = session.GetIdentifier(entity); var index = uncachedIds[id]; results[index] = entity; } } return results; } 

ここで力仕事をして非常に単純なLoadHelperクラスですか? –

+0

@DarrenKopp各IDに 'Load'を呼び出すと、複数のデータベースクエリが発行されます。私は既にキャッシュされたエンティティをスキップする単一のクエリが欲しい。 –

+2

必ずしもそうではありません。 Loadはプロキシを返しますが、クエリは発行しません。クエリは、オブジェクト上の何かにアクセスしたときに実行されますが、アクセスされるまではデータベースにクエリは実行されません。 NHibernateにはクエリのバッチ処理もありますので、ロードを1000回呼び出すことができ、バッチサイズが200の場合はデータベースに対して50のクエリしか取得できません。 –

答えて

0

Darren Koppのコメントは絶対に右である、バッチ処理が自動的にこれがあなたの代わりにISession.GetISession.Loadを使用することを忘れないでください、あなたはそれをすべて取得終了するまでは、プロキシオブジェクトのいずれかには触れないでください提供取り扱います。

しかし、遅延読み込みやバッチ処理が有効になっていない環境で私が思いついたもう1つの斬新な解決策を紹介したいと思いました。 DefaultLoadEventListenerクラスをサブクラス化し、LoadFromDatasourceメソッドからnullを戻すことで、データベースに触れずに第1レベルまたは第2レベルのキャッシュに存在するエンティティをロードすることができます。次に、欠落しているエンティティを1つのINクエリで取得し、順序付けられた結果の集まりに組み込むという単純な問題です。

private class LoadHelper : DefaultLoadEventListener 
{ 
    protected override object LoadFromDatasource(LoadEvent evt, 
               IEntityPersister persister, 
               EntityKey keyToLoad, 
               LoadType options) 
    { 
     return null; 
    } 
} 
0
var entities = adhocIds 
    .Select(session.Load<TEntity>) 
    .ToList(); 

var notloaded = entities 
    .Where(entity => !NHibernateUtil.IsInitialized(entity)) 
    .Select(session.GetIdentifier) 
    .ToList(); 

// we don't need the resultset, we just load it 
// so the proxies hit the cache instead of the DB 
session.CreateCriteria<TEntity>() 
    .Add(Restrictions.In(Projections.Id(), notloaded)) 
    .List(); 

return entities; 
+0

これは理にかなっていますが、セッション全体では機能しません。 'Session.Load'は、エンティティが第2レベルのキャッシュで第1レベルのキャッシュではない場合、初期化されていないプロキシを返します。 –

+0

@NathanBaulch素晴らしいリファクタリング。私はそれがクエリとその結果をキャッシュすると思ったNH第2のlvlキャッシュの専門家ではない。別のクエリ(異なるIDを持つRestrictions.In)が同じ結果を返すことをどのように知ることができますか?私はそれがクエリのセマンティクスを分析すると思いません – Firo

関連する問題