我需要根据临时ID列表高效加载大量实体。不幸的是,在进行Restrictions.In(Projections.Id(), ids)
条件查询时,它看起来不像是第二级缓存。
我想我正在寻找类似于ISession.Load
的东西,它带有一组ID(而不是一个),并且只对第一个或第二个中找不到的实体执行IN查询级别缓存。如果不存在这样的情况,那么在不诉诸反射的情况下手动检查两个缓存的最简单方法是什么?
答案 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;
}
}