2010-11-05 62 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