Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何正确使用NHibernate会话对象-会话已关闭!错误_Nhibernate_Design Patterns - Fatal编程技术网

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

如何正确使用NHibernate会话对象-会话已关闭!错误,nhibernate,design-patterns,Nhibernate,Design Patterns,我在NHibernate遇到了一些问题。我一直在关门!错误。请告诉我正确的模式,包括以下方法的定义,以及何时使用这些方法: ISession.Close() ISession.Dispose() ISession.Disconnect() 这是我的问题。我有一个回调设置来启动一个进程,每隔几分钟给玩家颁发一次徽章。然而,我总是让会议关闭!错误或关于无法关联集合的错误 这是我的存储库: public class NHibernateRepository : IRepository { #regi

我在NHibernate遇到了一些问题。我一直在关门!错误。请告诉我正确的模式,包括以下方法的定义,以及何时使用这些方法:

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

}

您应该始终使用session.Dispose;
另一个是针对非常奇怪的事件

我建议您阅读上的ISession文档

无论如何,当您完成会话时,正确的清理方法是处置它,或者更好地使用using语句来围绕用法。在这种情况下,使用将关闭会话并抑制终结器,即,它将防止会话对象在下一次垃圾收集中不必要地存活下来,并保存内存

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

文档建议调用disconnect而不是Close,因为这会释放到连接池的连接。在使用断开连接的会话之前,应先调用Reconnect


出于我的需要,我总是使用which调用Dispose,从来没有使用过其他两个函数。

问题在于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,而是调用存储过程。无论如何,我认为在我的情况下,它的性能更高。

关于这个问题,只要您处理了会话,您的锁定方法是正确的,但可能错误存在于代码的另一部分之下。顺便说一下,由于会话的工作单元实现和聚合根的事务,因此最好将会话变量传递给存储库,如下所示:

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

我正在使用调用dispose的using语句。但我仍然会犯错误,而且这种情况并非总是发生。只是有些时候。是的,我是一个web应用程序,但我没有将NHibernate会话与web会话集成。这个存储库在其他地方使用吗?因为,另一个OpenSession调用将丢失第一个。但他正在使用“using”不是吗。。。usingsession=\u repository.OpenSessionInteresting-您使用的是哪个ISessionFactory实现?他们说实现者必须是线程安全的。这正是问题所在。实现者必须是线程安全的,因为SessionFactory不是线程安全的。对,但哪个具体的ISessionFactory实现?SessionFactoryImpl?我相信如果你能重现这个问题,或者更好的是,找到bug,NHibernate团队会有兴趣听到它。Micah,这让我很困惑:我真的认为SessionFactory是线程安全的,根据NHibernate文档:ISessionFactory是一个昂贵的创建,要由所有应用程序线程共享的线程安全对象。我将继续我的项目,假设这是真的,您或者使用了错误的实现,或者错误存在于其他地方。