每个人都知道会话中有缓存。 通常可以通过2种方法清除此缓存:
第二种方法不仅删除单个条目的所有缓存。
我有商业方法。它接收大对象的id(来自aspx站点)或有时是几个id。并在数据库中执行本机sql操作(使用具有复杂逻辑的sql-query来不加载C#中的所有数据)。然后我需要使缓存无效。因此,每个潜在的对象负载都没有直接来自数据库的缓存。
不幸的是,evict只接受对象。此外,它的实现DefaultEvictEventListener在代码路径中有明确的分离 - 对于代理而不是代理类是分开的。我试过简单地创建实体,手动填充id并将其传递给Evict。这不行。据我所知,Evict没有代理类使用GetHashCode来从缓存中查找和删除对象。所以如果我没有压倒它就行不通。我有很多本机sql批处理操作,所以覆盖所有实体对象中的所有GetHashcode将创建大量工作。此外,我不确定这种情况是从缓存中删除代理还是否。 更新:据我所知,覆盖GetHashCode也没有帮助。 StatefulPersistenceContext.RemoveEntry未找到实体,因为它使用RuntimeHelpers.GetHashCode。所以这个解决方案甚至不可能
使用NHibernate的来源我已经提出了以下解决方案:
public static class NHSessionHelper: DefaultEvictEventListener
public static void RemoveEntityFromCache(this ISession session, Type type, object entityId)
{
ISessionImplementor sessionImpl = session.GetSessionImplementation();
IPersistenceContext persistenceContext = sessionImpl.PersistenceContext;
IEntityPersister persister = sessionImpl.Factory.GetEntityPersister(type.FullName);
if (persister == null)
{
return;
}
EntityKey key = new EntityKey(entityId, persister, sessionImpl.EntityMode);
persistenceContext.RemoveProxy(key);
object entity = persistenceContext.RemoveEntity(key);
if (entity != null)
{
EntityEntry e = persistenceContext.RemoveEntry(entity);
DoEvict(entity, key, e.Persister, (IEventSource)sessionImpl);
}
}
它只使用NHibenate实现的一部分。但在我看来,复制代码并不是一个好主意。可能有人有其他想法吗?
答案 0 :(得分:9)
如果您确定该对象位于缓存中,则Session.Get(id)
将不会访问该数据库。这可能是最简单的,然后Evict
你得到的对象:
Model m = Session.Get(id);
Session.Evict(m);
修改
我不清楚你是在谈论第一级缓存还是第二级缓存。以上将从第一级缓存中逐出。要从二级缓存中逐出,请在SessionFactory
上使用逐出法。
编辑以回复评论
在这种情况下,您可以尝试Session.Load
:
Model m = Session.Load(id);
Session.Evict(m);
如果m
位于缓存中,Session.Load
将返回您可以逐出的实例。如果不是,则返回代理(没有数据库命中)。我的测试表明,如果你试图驱逐代理,Session.Evict
将不会抛出,所以这应该有效。
答案 1 :(得分:2)
听起来你可以使用无状态会话,而不用担心缓存。