通过缓存支持高效加载多个ad hoc NHibernate实体

时间:2012-01-31 03:10:27

标签: .net nhibernate caching criteria

我需要根据临时ID列表高效加载大量实体​​。不幸的是,在进行Restrictions.In(Projections.Id(), ids)条件查询时,它看起来不像是第二级缓存。

我想我正在寻找类似于ISession.Load的东西,它带有一组ID(而不是一个),并且只对第一个或第二个中找不到的实体执行IN查询级别缓存。如果不存在这样的情况,那么在不诉诸反射的情况下手动检查两个缓存的最简单方法是什么?

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分:0)

Darren Kopp的评论是绝对正确的,如果你记得使用ISession.Load而不是ISession.Get,并且你没有触及任何代理对象,那么批处理会自动处理这个问题。已经完成了所有这些。

但是我想我会分享另一个新的解决方案,我提出了没有启用延迟加载或批处理的环境。通过继承DefaultLoadEventListener类并从LoadFromDatasource方法返回null,如果实体存在于第一级或第二级缓存中而不触及数据库,则可以加载该实体。然后,在一个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;
    }
}