我已经使用 NHibernate 一段时间了,并且不时发现如果我尝试同时请求两个页面(或尽可能接近),它偶尔会出错。所以我认为这是因为我的会话管理不是线程安全的。
我以为这是我的课,所以我尝试使用与这篇博文不同的方法http://pwigle.wordpress.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way/但是我仍然遇到同样的问题。我得到的实际错误是:
Server Error in '/AvvioCMS' Application.
failed to lazily initialize a collection, no session or session was closed
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: NHibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
要么打开要么没有打开数据读取器,但这是罪魁祸首。
我把我的会话管理课程放在下面,有人能发现我为什么会遇到这些问题吗?
public interface IUnitOfWorkDataStore
{
object this[string key] { get; set; }
}
public static Configuration Init(IUnitOfWorkDataStore storage, Assembly[] assemblies)
{
if (storage == null)
throw new Exception("storage mechanism was null but must be provided");
Configuration cfg = ConfigureNHibernate(string.Empty);
foreach (Assembly assembly in assemblies)
{
cfg.AddMappingsFromAssembly(assembly);
}
SessionFactory = cfg.BuildSessionFactory();
ContextDataStore = storage;
return cfg;
}
public static ISessionFactory SessionFactory { get; set; }
public static ISession StoredSession
{
get
{
return (ISession)ContextDataStore[NHibernateSession.CDS_NHibernateSession];
}
set
{
ContextDataStore[NHibernateSession.CDS_NHibernateSession] = value;
}
}
public const string CDS_NHibernateSession = "NHibernateSession";
public const string CDS_IDbConnection = "IDbConnection";
public static IUnitOfWorkDataStore ContextDataStore { get; set; }
private static object locker = new object();
public static ISession Current
{
get
{
ISession session = StoredSession;
if (session == null)
{
lock (locker)
{
if (DBConnection != null)
session = SessionFactory.OpenSession(DBConnection);
else
session = SessionFactory.OpenSession();
StoredSession = session;
}
}
return session;
}
set
{
StoredSession = value;
}
}
public static IDbConnection DBConnection
{
get
{
return (IDbConnection)ContextDataStore[NHibernateSession.CDS_IDbConnection];
}
set
{
ContextDataStore[NHibernateSession.CDS_IDbConnection] = value;
}
}
}
我正在使用的实际商店是这样的:
public class HttpContextDataStore : IUnitOfWorkDataStore
{
public object this[string key]
{
get { return HttpContext.Current.Items[key]; }
set { HttpContext.Current.Items[key] = value; }
}
}
我在 Application_Start 上初始化 SessionFactory:
NHibernateSession.Init(new HttpContextDataStore(), new Assembly[] {
typeof(MappedClass).Assembly});
更新
谢谢你的建议。我尝试了一些不同的方法来尝试简化代码,但我仍然遇到相同的问题,我可能知道原因。
我在需要时为每个请求创建会话,但在我的 global.asax 中,我正在处理 Application_EndRequest 上的会话。但是,当我在加载页面结束时进行调试时,我发现 Application_EndRequest 被多次触发。我认为该事件只假设在请求结束时触发一次,但如果不是,并且其他一些项目正在尝试使用 Session (这是错误所抱怨的),无论出于什么奇怪的原因可能是我的问题,会话仍然是线程安全的,它只是被提前处理掉了。
有人有什么想法吗?我做了一个谷歌,看到 VS 开发服务器确实会导致这样的问题,但我是通过 IIS 运行它。