2009-09-24 54 views
9

我遇到了NHibernate中我的ISessions問題。我不斷收到「Session Closed!」錯誤。有人可以告訴我正確的模式,包括以下方法的定義以及何時使用:如何正確使用NHibernate ISession對象 - 會話關閉!錯誤

ISession.Close() 
ISession.Dispose() 
ISession.Disconnect() 

這是我的問題。我有一個回調設置來觸發一個過程,每隔幾分鐘向玩家頒發一次徽章。但是我不斷收到「會話關閉!」無法關聯集合的錯誤或錯誤。

這裏是我的倉庫:

public class NHibernateRepository : IRepository 
{ 
#region Fields 

private ISession _session; 
private readonly ISessionFactory _sessionFactory; 
#endregion 

#region Constructors 

public NHibernateRepository(ISessionFactory sessionFactory) 
{ 
    _sessionFactory = sessionFactory; 
} 

#endregion 

#region IRepository Implementation 

public ISession OpenSession() 
{ 
    _session = _sessionFactory.OpenSession(); 
    return _session; 
} 

public IQueryable<TModel> All<TModel>() 
{ 
    return _session.Linq<TModel>(); 
} 

public void Save<TModel>(TModel model) 
{ 
    _session.Save(model); 
} 
public void Update<TModel>(TModel model) 
{ 
    _session.Update(model); 
} 
public void Delete<TModel>(TModel model) 
{ 
    _session.Delete(model); 
} 

public ITransaction BeginTransaction() 
{ 
    return _session.BeginTransaction(); 
} 
public void Flush() 
{ 
    _session.Flush(); 
} 
#endregion 

} 

這是我的使用情況。該存儲庫正在通過結構圖注入

private Object _awardBadgesLock = new object(); //In case the callback happens again before the previous one completes 

public void AwardBadges() 
{ 

    lock (_awardBadgesLock) 
    { 
     using(session = _repository.OpenSession()) 
     { 
      foreach (var user in _repository.All<User>().ToList()) 
      { 
       var userPuzzles = _repository.All<Puzzle>().ByUser(user.Id).ToList(); 
       var userVotes = _repository.All<Vote>().Where(x => x.UserId == user.Id).ToList(); 
       var userSolutions = _repository.All<Solution>().ByUser(user.Id).ToList().Where(x => !userPuzzles.Select(y => y.Id).Contains(x.PuzzleId)); 
       var ledPuzzles = GetPuzzlesLedByUser(user.Id); 

       AwardPlayerBadge(user, userSolutions); 
       AwardCriticBadge(user, userVotes); 
       AwardCreatorBadge(user, userPuzzles); 
       AwardRidlerBadge(user, userPuzzles); 
       AwardSupporterBadge(user, userVotes); 
       AwardPopularBadge(user, userPuzzles); 
       AwardNotableBadge(user, userPuzzles); 
       AwardFamousBadge(user, userPuzzles); 
       AwardLeaderBadge(user, ledPuzzles); 

       using (var tx = _repository.BeginTransaction()) 
       { 
        _repository.Update(user); 
        tx.Commit(); 
       } 
      } 
     } 
    } 

} 
+0

這是一個網絡應用程序? – mxmissile 2009-09-24 17:37:06

+0

是的,我沒有一個網絡應用程序,但我沒有將NHibernate會話與Web會話進行整合。 – Micah 2009-09-24 18:09:33

+3

_repository是否在其他地方使用?因爲,另一個OpenSession()調用將失去第一個。 – dotjoe 2009-09-24 18:58:00

回答

0

問題在於ISession不是線程安全的。在單獨的線程上觸發了多個方法,這些方法都創建了一個ISession實例。這個問題的確是因爲它們都共享了相同的SessionFactory。像這兩種方法都在單獨的線程發射了:

ISessionFactory _sessionFactory; 

void MethodOne() 
{ 
    using(ISession session = _sessionFactory.OpenSession()) 
    { 
     //Do something with really quick with the session 
     //Then dispose of it 
    } 
} 

void MethodTwo() 
{ 
    //OpenSession() actually returns the same instance used in the 
    //previous method that has already disposed of the object; 
    using(ISession session = _sessionFactory.OpenSession()) 
    { 
     //Do something with a session that has already been disposed 
     //throws errors 

    } 
} 

我如何固定它基本上在這些場景開溝NHibernate和調用的存儲特效來代替。無論如何,我認爲它在我的情況下表現得更加出色。

+2

有趣的 - 你正在使用哪個'ISessionFactory'實現? [接口的文檔](https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/ISessionFactory.cs)說「實現者必須是線程安全的。」 – 2010-09-30 13:20:15

+0

這就是問題所在。 「實現者必須是線程安全的」,因爲SessionFactory不是線程安全的。 – Micah 2010-09-30 15:02:46

+5

對,但*具體的'ISessionFactory'實現? 'SessionFactoryImpl'?我確定如果你能重現這個問題(或者更好的話,找到[源代碼中的錯誤]](https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/Impl /SessionFactoryImpl.cs)),NHibernate團隊會對此感興趣。 – 2010-09-30 15:37:59

13

您應該始終使用session.Dispose(); 其他都是非常奇怪occurances

+4

我正在使用調用處理的「using」語句。儘管如此,我仍然遇到了錯誤,而且這種情況並不總是發生。只是有些時候。 – Micah 2009-09-24 18:06:13

6

我建議你,當你完成會話後讀的Isession的文檔上 https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/ISession.cs

反正清理正確方法是處理它(或更好地使用語句來包圍用法)。在這種情況下,「使用」關閉會話並禁止終結器,即它阻止會話對象不必要地繼續下一次垃圾收集並保存內存。

如果連接已經關閉,處理它不會拋出異常。另一方面,處置後(或關閉後)關閉引發異常。

文檔建議調用disconnect而不是關閉,因爲這會釋放與連接池的連接。您應該在使用斷開連接的會話之前調用重新連接。

爲了我的需要,我總是使用「使用」,它調用Dispose並從未使用過其他兩個函數。

+2

但他使用'使用'不是嗎? ...使用(session = _repository.OpenSession()) – UpTheCreek 2009-11-10 17:42:30

0

關於這個問題,只要您處理會話,您的鎖定方法就是正確的,但可能錯誤在於您的代碼的另一部分。約設計的方式,倒不如說你通過會話變量的存儲庫,因爲工作落實會議和聚合根的交易像這樣的單位:

using (ISession session = SessionFactory.OpenSession()) 
{ 
    Repository1 rep1 = new Repository1(session); 
    Repository2 rep1 = new Repository2(session); 
    Repository3 rep1 = new Repository3(session); 

    // some logics 

    using (var tx = session.BeginTransaction()) 
     tx.Commit(); 
} 

。 。 。