ORM として NHibernate を使用して C# MVC 3 を作成しましたが、ほとんどのページの読み込みで奇妙な例外がスローされます。それらは主にクローズドセッションなどに関連しているようで、一般的な問題のほとんどを確認しましたが、ほとんど役に立ちませんでした. 例外には次のようなものがあります。
[[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.
例外の壁についてお詫び申し上げます。それらは関連していると思われますが、コードに別のエラーが発生し、1 つまたは 2 つのエラーが発生する可能性があります。これらのことに対してランダムという言葉を使用するのは好きではありませんが、それらを呼び出す特定のコード行を追跡できないようです.ISessionオブジェクトに関連するコード行に表示されるようです. Global.asax ファイルの BeginTranscation メソッドで "Session is closed" 例外がスローされたことさえあります。
アプリケーションは、hibernate.cfg.xml で current_session_context_class の Web オプションを使用します。
私の疑いは、それが私のセッション管理コードに関連していることです。Web サイトは通常、約 10 個の AJAX リクエストを同時にロードします。複数のページが同時にロードされると、エラーがより頻繁に発生するようです。使用されるデータベースごとに 1 つずつ、合計 2 つのセッション ファクトリがあります。
関連する 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 で開始されない場合もあれば、コミットされない場合もあれば、どちらでもない場合もあります。そして最も不可解なことに、それらは 3 回開始されても終了しないことがあります。
ISession オブジェクトへのすべての呼び出しは、次のコードによって管理されます (ファクトリごとに 1 つずつあります)。
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 への呼び出しはありません。皆さんがこれに当てることができる光は大歓迎です!