我在NHibernate中遇到了我的ISessions问题。我一直在“会议结束!”错误。有人可以告诉我正确的模式,包括以下方法的定义以及何时使用每种方法:
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
}
这是我的用法。存储库通过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();
}
}
}
}
}
答案 0 :(得分:13)
你应该总是使用session.Dispose(); 另一个是非常奇怪的出现
答案 1 :(得分:6)
我建议你阅读ISession的文档 https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/ISession.cs
无论如何,当你完成会话时清理的正确方法是处理它(或者更好,用using语句包围使用)。在这种情况下,“使用”会关闭会话并抑制终结器,即它会阻止会话对象不必要地幸免于下一次垃圾收集并保存内存。
如果连接已经关闭,处理它不会引发异常。另一方面,处理后(或关闭后)关闭会引发异常。
文档建议调用disconnect而不是关闭,因为这会释放与连接池的连接。您应该在使用断开连接的会话之前调用重新连接。
根据我的需要,我总是使用“使用”调用Dispose并且从未使用过其他两种功能。
答案 2 :(得分: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
}
}
我如何修复它基本上是在这些场景中抛弃NHIbernate并改为调用存储过程。无论如何,我觉得它在我的情况下表现得更好。
答案 3 :(得分: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();
}
。 。