Я написал C # MVC 3 с NHibernate в качестве ORM, и у меня возникают некоторые странные исключения при загрузке большинства страниц. Похоже, они в основном относятся к закрытым сессиям и т.п., и я проверил большинство распространенных проблем, но мало что помогло. Некоторые исключения включают:
[[NHibernate.Util.ADOExceptionReporter]] : System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
at System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command)
[[NHibernate.Transaction.AdoTransaction]] : Begin transaction failed
System.Data.SqlClient.SqlException (0x80131904): The server failed to resume the transaction. Desc:3b00000006.
[[NHibernate.Transaction.AdoTransaction]] : Commit failed
System.NullReferenceException: Object reference not set to an instance of an object.
[[NHibernate.Transaction.AdoTransaction]] : Commit failed
System.Data.SqlClient.SqlException (0x80131904): The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
[[NHibernate.Util.ADOExceptionReporter]] : System.InvalidOperationException: The transaction is either not associated with the current connection or has been completed.
at System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async)
[[NHibernate.Transaction.AdoTransaction]] : Begin transaction failed
System.InvalidOperationException: SqlConnection does not support parallel transactions.
Прошу прощения за стену исключений, я подозреваю, что они связаны, но потенциально может быть еще одна ошибка в коде, вызывающая одну или две. Мне не нравится использовать слово «случайный» для этих вещей, но я не могу отследить какую-либо конкретную строку кода, которая их вызывает, они просто появляются в строках кода, относящихся к объектам ISession. У меня даже было исключение «Сеанс закрыт» в методе BeginTranscation в моем файле Global.asax.
Приложение использует веб-параметр current_session_context_class в hibernate.cfg.xml.
Я подозреваю, что это связано с моим кодом управления сеансом. Веб-сайт обычно загружает около 10 одновременных запросов AJAX, и кажется, что ошибки возникают чаще, когда одновременно загружаются несколько страниц. Есть две фабрики сеансов, по одной для каждой используемой базы данных.
Вот мой соответствующий код Global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
_sessionFactory = (new WebClientSessionManager()).MakeSessionFactory();
_sessionFactoryNotWeb = ClientSessionManager.MakeSessionFactory();
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
_session = _sessionFactory.OpenSession();
_sessionNotWeb = _sessionFactoryNotWeb.OpenSession();
CurrentSessionContext.Bind(_sessionNotWeb);
CurrentSessionContext.Bind(_session);
_session.BeginTransaction();
_sessionNotWeb.BeginTransaction();
}
protected void Application_EndRequest(object sender, EventArgs e)
{
//Same code is repeated for the _sessionFactoryNotWeb
ISession session = CurrentSessionContext.Unbind(_sessionFactory);
if (session != null)
{
if (session.Transaction.IsActive)
{
try
{
session.Transaction.Commit();
}
catch
{
session.Transaction.Rollback();
}
}
try
{
session.Dispose();
}
catch
{
}
}
Я просмотрел страницу, работающую в профилировщике NHibernate. Иногда сеансы не запускаются с помощью BeginTranscation, иногда они не фиксируются, иногда нет; и, что самое удивительное, иногда они запускаются трижды, но не заканчиваются.
Любые вызовы объекта ISession управляются с помощью этого кода (по одному для каждой фабрики):
public static ISession WebSession()
{
if (CurrentSessionContext.HasBind(MvcApplication._sessionFactory))
{
if (MvcApplication._sessionFactory.GetCurrentSession().IsOpen)
{
return MvcApplication._sessionFactory.GetCurrentSession();
}
else
{
log4net.LogManager.GetLogger(typeof(DBHandler)).Debug("Unbinding NHibernate session");
CurrentSessionContext.Unbind(MvcApplication._sessionFactory);
return WebSession();
}
}
else
{
log4net.LogManager.GetLogger(typeof(DBHandler)).Debug("Initialising NHibernate session");
var session = MvcApplication._sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
session.BeginTransaction();
return session;
}
}
В приложении нет вызовов BeginTransaction или Commit без их сброса, фиксации, удаления сеанса и повторного открытия в соответствии с приведенным выше кодом. Мы будем очень признательны за любой свет, который вы могли бы пролить на это!