如何正确使用NHibernate ISession对象 - 会话已关闭!错误 [英] How to properly use a NHibernate ISession object - Session Is Closed! errors

查看:215
本文介绍了如何正确使用NHibernate ISession对象 - 会话已关闭!错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在NHibernate中遇到了我的会话问题。我一直在会话关闭!错误。有些人可以向我显示正确的模式,包括以下方法的定义和何时使用每个方法:

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

这是我的问题。我有一个回调设置,以消除每几分钟向玩家颁发徽章的过程。但是我不断得到会话关闭!



这是我的存储库:

  public class NHibernateRepository:IRepository 
{
#region Fields

private ISession _session;
private readonly ISessionFactory _sessionFactory;
#endregion

#region构造函数

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

#endregion

#region IRepository实现

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

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

public void保存< TModel>(TModel模型)
{
_session.Save(model);
}
public void Update< TModel>(TModel model)
{
_session.Update(model);
}
public void删除< TModel>(TModel模型)
{
_session.Delete(model);
}

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

}

我的用法存储库通过结构图注入

  private Object _awardBadgesLock = new object(); //如果在前一个完成之前再次发生回调

public void AwardBadges()
{

lock(_awardBadgesLock)
{
使用(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>()。其中​​(x => x.UserId == user.Id).ToList();
var userSolutions = _repository.All< Solution>()。ByUser(user.Id).ToList()。其中​​(x =>!userPuzzles.Select(y => y.Id) .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(用户,led拼图);

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

}


解决方案

问题在于ISession不是线程安全的事实。在单独的线程上触发了多个方法,所有这些方法都创建了一个ISession的实例。这个问题真的是他们都共享了相同的SessionFactory。图像这两种方法都在单独的线程上触发:

  ISessionFactory _sessionFactory; 

void MethodOne()
{
using(ISession session = _sessionFactory.OpenSession())
{
//使用session
//然后处理
}
}

void MethodTwo()
{
// OpenSession()实际返回在已经处理该对象的
//以前的方法中使用的相同实例;
using(ISession session = _sessionFactory.OpenSession())
{
//对已经被处理的会话进行某些事情
//抛出错误

}
}

我如何修正它在这些情况下基本上是缩小NHIbernate,存储procs而不是。我认为事实证明在我的情况下更加出色。


I'm running into issues with my ISessions in NHibernate. I keep getting "Session Closed!" errors. Can some one please show me the correct pattern including a definition of the following methods and when to use each:

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

Here's my problem. I have a callback setup to fire off a process that awards badges to players every couple of minutes. However I keep getting "Session Closed!" errors or errors about not being able to associate collections.

Here's my Repository:

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

}

Here's my usage. The repository is getting injected via 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();
                }
            }
        }
    }

}

解决方案

The issue lies in the fact the ISession is not thread-safe. There were multiple methods being fired on separate threads that all created an instance of ISession. The issue was really with the fact that they all shared the same SessionFactory. Image both of these methods are fired off on separate threads:

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

   }
}

How I fixed it was basically ditching NHIbernate in these scenarios and called stored procs instead. I think it turned out to be more performant in my situation anyway.

这篇关于如何正确使用NHibernate ISession对象 - 会话已关闭!错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆