絶対最新バージョン (3.3) を使用し、HttpModule 内でセッションごとのセッション管理を使用している Web アプリケーションがあるため、複数のセッションの競合に問題はありません。残念ながら、Transaction.Commit を実行した直後にセッションが自動的に閉じられることがわかりました。これは、実際に作成、更新、または削除を実行しているときにのみ行います。NHibernate ログ内でこれを見つけています。
ISession.Close 関数への唯一の呼び出しが HttpModule 内で行われているため、私はそれを行っていないという事実を知っています。
はい、もちろん、SessionManager にコードを挿入して IsClosed パラメータをチェックし、GetCurrentSession の代わりに OpenSession 関数を使用することはできますが、これは実際に行われるべきでしょうか? 構成またはセッションまたはトランザクションオブジェクトに設定できる属性を介してこれを防ぐ方法はありますか、それともドキュメントが見つからない新機能の 1 つにすぎませんか?
助けてください。
ブライアン
コードを提供するように求められたので、HttpModule のコードを次に示します。
public class NhibernateModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
context.EndRequest += new EventHandler(context_EndRequest);
}
public void context_BeginRequest(Object sender, EventArgs e)
{
WebSessionContext.Bind(NhibernateSessionManager.GetContextSession());
}
public void context_EndRequest(Object sender, EventArgs e)
{
ISession session = WebSessionContext.Unbind(NhibernateSessionManager.SessionFactory);
if (session != null)
{
if (session.Transaction != null && session.Transaction.IsActive)
{
session.Transaction.Rollback();
}
else
session.Flush();
session.Close();
}
}
}
}
次に、SessionManager 内で使用している元のコードを見つけます。
public sealed class NhibernateSessionManager
{
private readonly ISessionFactory sessionFactory;
public static ISessionFactory SessionFactory
{
get { return Instance.sessionFactory; }
}
private ISessionFactory GetSessionFactory()
{
return sessionFactory;
}
public static NhibernateSessionManager Instance
{
get { return NestedSessionManager.sessionManager; }
}
public static ISession GetContextSession()
{
ISession session;
if (CurrentSessionContext.HasBind(SessionFactory))
{
session = SessionFactory.GetCurrentSession();
}
else
{
session = SessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
}
return session;
}
private NhibernateSessionManager()
{
if (sessionFactory == null)
{
Configuration configuration;
configuration = new Configuration().Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web.config"));
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web.config")));
//Configuration configuration = new Configuration().Configure();
if (configuration == null)
{
throw new InvalidOperationException("NHibernate configuration is null.");
}
else
{
sessionFactory = configuration.BuildSessionFactory();
if (sessionFactory == null)
throw new InvalidOperationException("Call to BuildSessionFactory() returned null.");
}
}
}
class NestedSessionManager
{
internal static readonly NhibernateSessionManager sessionManager = new NhibernateSessionManager();
}
}
最後に、現在 Transaction.Commit() の直後にセッションを終了させている関数があります。各内部関数は、現在のセッションを取得してから、Save 呼び出しを処理します。
public static Int32 AddVideo(VideoFile Video, Int32 UserID, Int16 InstID)
{
log.Debug("Begin AddVideo");
Int32 FileID = 0;
using (ISession Session = NhibernateSessionManager.GetContextSession())
{
using (ITransaction Transaction = Session.BeginTransaction())
{
Video.Created = DateTime.Now;
Video.Modified = DateTime.Now;
FileID = (Int32)Session.Save(Video);
Video.FileID = FileID;
// Need to process through all the categories and insert records into the ivxFileCategories table
// to associate the newly created file with the chosen categories
if (Video.CategoryAssociations != null)
{
log.Info("Number of categories to be associated with the video: " + Video.CategoryAssociations.Count);
for (int i = 0; i < Video.CategoryAssociations.Count; i++)
{
CategoryFileAssociation Assoc = (CategoryFileAssociation)Video.CategoryAssociations[i];
Assoc.FileID = FileID;
AssociationManager.AddCategoryFileTransaction(Assoc);
}
}
// Need to add the default file access for the UserDetail that is creating the new video which will always
// be Admin because the UserDetail creating a file should always have admin access over the file, no matter
// what their default role is.
AssociationManager.AddFileAccessTransaction(FileID, UserID, UserClassConstants.IVXUSERCLASS_ADMIN);
// Need to add the institutional association based on whether the new video was created by a librarian
// or one of the iVidix admins
AssociationManager.AddInstitutionFileTransaction(InstID, FileID);
Transaction.Commit();
}
}
log.Debug("End AddVideo");
return FileID;
}