2009-09-24 40 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(); 
} 

。 。 。