2012-01-31 3 views
2

Мне нужно эффективно загружать большое количество объектов на основе списка ad hoc ID. К сожалению, это не похоже на то, что кеш второго уровня проверяется сначала при выполнении Restrictions.In(Projections.Id(), ids) критериев запросов.Эффективная загрузка нескольких специальных объектов NHibernate с поддержкой кеша

Я думаю, что я ищу что-то похожее на ISession.Load, которое берет набор идентификаторов (а не только один) и выполняет только запрос IN для объектов, которые не могут быть найдены в кешах 1 или 2 уровня. Если ничего подобного не существует, то какой самый простой способ проверить два кэша вручную, не прибегая к размышлению?

+0

Что случилось с Session.load? –

+0

@DarrenKopp Вызов 'Load' для каждого идентификатора будет выдавать несколько запросов к базе данных. Я хочу, чтобы один запрос пропускал уже кэшированные объекты. –

+2

Не обязательно. Загрузка будет возвращать прокси, но не будет выдавать запрос. Запрос выполняется, когда что-то на объекте обращается, но до его обращения он не будет запрашивать базу данных. NHibernate также имеет пакетную обработку запросов, поэтому вы можете вызвать нагрузку в тысячу раз и с размером партии 200, получить только 50 запросов к базе данных. –

ответ

0

Darren Kopp «s комментарий абсолютно прав, пакетирование автоматически обрабатывает это при условии, вы помните, чтобы использовать ISession.Load вместо ISession.Get и не прикасайтесь ни к каким объектам прокси до тех пор, пока вы закончите подгружать их всех.

Однако я решил поделиться другим новым решением, которое я придумал для сред, которые не имеют ленивой загрузки или пакетной обработки. Подклассифицируя класс DefaultLoadEventListener и возвращая null из метода LoadFromDatasource, можно загрузить объект, если он существует в кешах 1 или 2 уровня, не касаясь базы данных. Это просто вопрос получения отсутствующих объектов в одном запросе IN и переплетения их в упорядоченный набор результатов.

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 класс, который делает тяжелую работу:

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' возвращает неинициализированный прокси-сервер, если объект находится в кеше второго уровня, а не кеше 1-го уровня. –

+0

@NathanBaulch хороший рефакторинг. Я не эксперт в NH 2nd lvl caches, но я думал, что он кэширует запросы и их результат. Как он может знать, что другой запрос (Restrictions.In с differnd id) возвращает те же результаты? Я не думаю, что он анализирует семантику запроса – Firo

Смежные вопросы