如何正确使用NHibernate ISession对象 - 会话已关闭!错误

Mic*_*cah 9 nhibernate design-patterns

我在NHibernate中遇到了ISessions的问题.我一直在"会议结束!" 错误.有人可以告诉我正确的模式,包括以下方法的定义以及何时使用每种方法:

ISession.Close()
ISession.Dispose()
ISession.Disconnect()
Run Code Online (Sandbox Code Playgroud)

这是我的问题.我有一个回调设置来启动一个每隔几分钟向玩家颁发徽章的流程.但是我一直在"会议结束!" 关于无法关联集合的错误或错误.

这是我的存储库:

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

}
Run Code Online (Sandbox Code Playgroud)

这是我的用法.存储库通过Structure Map注入

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();
                }
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

Aye*_*ien 13

你应该总是使用session.Dispose(); 另一个是非常奇怪的事情

  • 我正在使用调用dispose的"using"语句.我仍然得到错误,但它不会一直发生.只是在某些时候. (4认同)

Mou*_*ouk 6

我建议你阅读https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/ISession.cs上的ISession文档

无论如何,当你完成会话时清理的正确方法是处理它(或者更好,用using语句包围使用).在这种情况下,"使用"关闭会话并抑制终结器,即它防止会话对象不必要地幸免于下一次垃圾收集并保存内存.

如果连接已经关闭,则处理它不会引发异常.另一方面,处理后(或关闭后)关闭会引发异常.

文档建议调用disconnect而不是关闭,因为这会释放与连接池的连接.您应该在使用断开连接的会话之前调用重新连接.

根据我的需要,我总是使用"使用"调用Dispose并且从未使用过其他两个函数.

  • 但他使用'使用'不是他吗?...使用(session = _repository.OpenSession()) (2认同)

Mic*_*cah 1

问题在于 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

   }
}
Run Code Online (Sandbox Code Playgroud)

我解决这个问题的方法基本上是在这些场景中放弃 NHIbernate 并调用存储过程。无论如何,我认为在我的情况下它的性能更高。

  • 是的,但是*哪个*具体的“ISessionFactory”实现?`SessionFactoryImpl`?我确信您是否可以重现该问题(或者更好的是,在源代码中找到错误)(https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/Impl /SessionFactoryImpl.cs)),NHibernate 团队有兴趣了解它。 (5认同)
  • 有趣 - 您使用哪个“ISessionFactory”实现?[接口的文档](https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/ISessionFactory.cs)说“实现器必须是线程安全的。” (2认同)