2010-11-05 59 views
6

大家都知道会话中有缓存。 这种缓存通常可以通过两种方法来清除:NHibernate驱逐编号

  1. Session.Evict
  2. Session.Clear

第二种方法去除不仅单次入境的所有缓存。

我有商业方法。它接收大对象的id(来自aspx站点)或有时候有几个id。在数据库中执行原生的sql操作(使用具有复杂逻辑的sql-query不加载C#中的所有数据)。然后我需要使缓存无效。因此,每个潜在的对象负载都不会从数据库直接缓存。

不幸的是驱逐只接受对象。此外,它的实现DefaultEvictEventListener在代码路径中有明确的分离 - 对于代理而不是代理类是分开的。我试图简单地创建实体,手工填写id并将其传递给Evict。这不会起作用。正如我所了解的Evict by not proxied class,使用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实现的一部分。但在我看来,复制代码似乎不是个好主意。可能有人有其他想法?

回答

9

如果您确定该对象在缓存中,则Session.Get(id)不会命中数据库。这可能是最容易做到这一点,然后Evict对象,你回来:

Model m = Session.Get(id); 
Session.Evict(m); 

编辑

这不是我清楚,如果你谈论的是第一级缓存或第二级缓存。以上将从第一级缓存中驱逐一些东西。要从二级缓存中驱逐,请使用SessionFactory上的evict方法。

编辑回应评论

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

Model m = Session.Load(id); 
Session.Evict(m); 

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

+0

这是正确的做法。获取返回模型的代理并设置ID – jonnii 2010-11-05 15:26:28

+0

我正在谈论第一级缓存。 我不确定它是否在缓存或否。有时它有时不是。 在这种情况下,我想从缓存中清除它。如果它不在缓存中,你的代码可能会对数据库产生真正的影响。所以我想要这两种情况下相同的代码。所以数据操纵操作只是确保缓存中没有数据。 – 2010-11-05 15:29:15

+0

关于上次“编辑回应评论”。如果在操作时它不会在Evict内部访问数据库,并且没有在缓存中的实体没有例外,那么我会说你的解决方案是最好的。 – 2010-11-05 15:50:57

2

这听起来像你可以使用无状态会话,而不用打扰缓存。

+0

我在想无国籍的会议。这是个好主意。但是我写了太多的代码(类似于152种商业方法)。如果我将全部更改为无状态会话。我会给很多代码来测试。至少所有操作都将使用相同类型的会话。在我看来,当某些DAO使用某种类型的sesison,而其他使用另一种类型的sesison时,并不是这样。 – 2010-11-05 15:35:40

+0

基本思想是当您要导航关系并更新持久对象时使用常规会话,以及当您只想运行查询并返回POCO对象时使用无状态会话。 – 2010-11-05 15:44:04