NHibernate通过id逐出

时间:2010-11-05 15:01:50

标签: nhibernate

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

  1. Session.Evict
  2. Session.Clear
  3. 第二种方法不仅删除单个条目的所有缓存。

    我有商业方法。它接收大对象的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实现的一部分。但在我看来,复制代码并不是一个好主意。可能有人有其他想法吗?

2 个答案:

答案 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)

听起来你可以使用无状态会话,而不用担心缓存。