我在 win 服务中使用 NHiberante。有时我得到
System.ObjectDisposedException: Session is closed!
Object name: 'ISession'.
at NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed()
at NHibernate.Impl.AbstractSessionImpl.CheckAndUpdateSessionStatus()
at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.Save(Object obj)
at Attraction.DAL.Repositories.Repository`1.Save(T entity)
at Attraction.VideoDispatcher.Program.ThreadPoolCallback(Object threadContext)
我不知道出了什么问题。我的会话管理子系统:
存储库:
public class Repository<T> : IRepository<T>, IDisposable
{
protected readonly bool CommitAtDispose;
public Repository(bool commitAtDispose)
{
CommitAtDispose = commitAtDispose;
StartSession();
}
private void StartSession()
{
if (NHibernateSession == null)
NHibernateHelper.StartSession();
}
public void Dispose()
{
if (CommitAtDispose)
Flush();
}
public void Flush()
{
NHibernateHelper.EndSession();
}
protected override sealed ISession NHibernateSession
{
get
{
return SessionManager.CurrentSession;
}
}
public virtual T GetById(int id)
public virtual List<T> GetAll()
public virtual List<T> GetByPage(int pageIndex, int pageSize)
public virtual int GetCount()
public virtual List<T> GetByCriteria(params ICriterion[] criterion)
public virtual T Save(T entity)
public virtual T Update(T entity)
public virtual void Delete(T entity)
}
}
SessionManager - 提供对 sessionfactory 的访问的单音
public class SessionManager : ISessionFactoryProvider
{
private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private readonly ISessionFactory sessionFactory;
public static ISessionFactory SessionFactory
{
get { return Instance.sessionFactory; }
}
public ISessionFactory GetSessionFactory()
{
return sessionFactory;
}
public static ISession OpenSession()
{
return Instance.GetSessionFactory().OpenSession();
}
public static ISession CurrentSession
{
get
{
if (!CurrentSessionContext.HasBind(Instance.GetSessionFactory()))
return null;
return Instance.GetSessionFactory().GetCurrentSession();
}
}
public static SessionManager Instance
{
get
{
return NestedSessionManager.sessionManager;
}
}
private SessionManager()
{
Log.Info("Start creating factory");
Configuration configuration = new Configuration().Configure();
sessionFactory = configuration.BuildSessionFactory();
Log.Info("End creating factory");
}
class NestedSessionManager
{
internal static readonly SessionManager sessionManager =
new SessionManager();
}
}
NhibernateHelper,它为开始和结束会话做一些工作:
public static class NHibernateHelper
{
public static void StartSession()
{
var session = SessionManager.SessionFactory.OpenSession();
session.BeginTransaction();
CurrentSessionContext.Bind(session);
}
public static void EndSession()
{
var session = SessionManager.CurrentSession;
CurrentSessionContext.Unbind(SessionManager.SessionFactory);
if (session != null)
{
try
{
if (session.Transaction != null && session.Transaction.IsActive)
session.Transaction.Commit();
}
catch (Exception ex)
{
session.Transaction.Rollback();
throw new ApplicationException("Error committing database transaction. "+ex.Message, ex);
}
finally
{
session.Close();
session.Dispose();
}
}
}
}
可能是我的设计不太好,但我无法想象我怎么能抓住这个错误。
UPD
对不起我的配置。我还没有迁移到流利的,所以:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MySQLDialect</property>
<property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
<property name="connection.connection_string">***</property>
<property name="show_sql">false</property>
<property name="default_schema">**_***</property>
<property name="current_session_context_class">thread_static</property>
<mapping assembly="***.Core"/>
</session-factory>
</hibernate-configuration>
UPD2
保存方法:
public virtual T Save(T entity)
{
NHibernateSession.Save(entity);
return entity;
}
线程池回调:
public static void DetectStart(Object threadContext)
{
try
{
var task = (TasksPerAttraction)threadContext;
var startInfo = new ProcessStartInfo(..., ...)
{
UseShellExecute = false,
RedirectStandardOutput = true
};
Process p = Process.Start(startInfo);
var outputXml = p.StandardOutput.ReadToEnd();
p.WaitForExit();
var doc = XDocument.Parse(outputXml);
foreach (var xElement in doc.Root.Descendants("start"))
{
var startDetection = new StartDetection
{
DtStart = DateTime.Parse(xElement.Attribute("startTime").Value),
Attraction = task.Attraction,
};
lock (spinLock)
{
using (var repo = new Repository<StartDetection>(true))
repo.Save(startDetection);
}
}
var tskRepo = new Repository<Task>(true);
foreach(var tsk in task.Tasks)
{
tsk.IsProcessedStart = true;
tskRepo.Update(tsk);
}
tskRepo.Flush();
}
catch (Exception ex)
{
//....
}
}