1

絶対最新バージョン (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;
    }
4

3 に答える 3

4

セッションにusing ステートメントを使用しているため、セッションは AddVideo メソッドで破棄されます。

using (ISession Session = NhibernateSessionManager.GetContextSession())
{

}
于 2012-05-01T21:25:42.060 に答える
1

トランザクションをコミットすると、そのセッションが終了します。

トランザクションの開始を context_BeginRequest に移動し、コミット/クリーンアップを context_EndRequest に移動します

私は実際にはビューパターンのセッションが好きではなく、トランザクションをできるだけ短く開いたままにして、コントローラーにセッションを挿入することを好みます。次に、アクションまたはサービスでトランザクションを実行します。私はトランザクションのこのきめ細かな制御を好み、ロックの問題を回避してトランザクションを短命に保ちます。

于 2012-05-02T12:03:26.240 に答える
1

トランザクションのものを取り除くことを完全にお勧めします

using (ISession Session = NhibernateSessionManager.GetContextSession())
{
  using (ITransaction Transaction = Session.BeginTransaction())
  {
   ...
  }
}

それを開始/終了リクエストに移動します。このようにして、forリクエストごとに UOW があります。セッションを閉じている理由は、using statement.

開始要求コードは、次の行に沿ったものにすることができます:-

var session = sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
session.BeginTransaction();

そしてあなたの最後の要求: -

var session = CurrentSessionContext.Unbind(sessionFactory);

if (session != null)
{
    if (session.Transaction.IsActive)
    {
        try
        {
            session.Transaction.Commit();
        }
        catch
        {
            session.Transaction.Rollback();
        }
    }
    session.Close();
}

私はglobal.asaxにこれを持っています

public static ISessionFactory SessionFactory { get; set; }

これは私のリポジトリにあります

    public ISession Session
    {
        get
        {
            return SessionFactory.GetCurrentSession();
        }
    }

ここで、IOC を使用して sessionFactory をリポジトリ レイヤーに渡します。それ以外の場合は、これを自分で手動で渡す必要があります。

于 2012-05-02T11:17:20.870 に答える