NHibernate通过id逐出

Yau*_*n.F 6 nhibernate

每个人都知道会话中有缓存.通常可以通过2种方法清除此缓存:

  1. Session.Evict
  2. Session.Clear

第二种方法不仅删除单个条目的所有缓存.

我有商业方法.它接收大对象的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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

它只是使用NHibenate实现的一部分.但在我看来重复代码并不是一个好主意.可能有人有其他想法吗?

Gab*_*art 9

如果您确定该对象位于缓存中,Session.Get(id)则不会命中该数据库.这可能是最容易做到的,然后Evict是你得到的对象:

Model m = Session.Get(id);
Session.Evict(m);
Run Code Online (Sandbox Code Playgroud)

编辑

我不清楚你是在谈论第一级缓存还是第二级缓存.以上将从第一级缓存中逐出.要从二级缓存中逐出,请使用evict方法SessionFactory.

编辑以回应评论

在这种情况下,您可以尝试Session.Load:

Model m = Session.Load(id);
Session.Evict(m);
Run Code Online (Sandbox Code Playgroud)

如果m在缓存中,Session.Load将返回您可以逐出的实例.如果不是,则返回代理(没有数据库命中).我的测试表明,Session.Evict如果你试图驱逐代理,不会抛出,所以这应该工作.