2

過去にセッション管理の問題が提起されたことは知っていますが、問題を解決するのに役立つものは何も見つかりませんでした。

Castle Windsorを介して解決するリポジトリクラス(CustomerRepository、ProductRepositoryなど)がいくつかあります(注:ここで概説する3つの呼び出しパターンを適用しようとしています)。プレゼンターごとにセッションを作成するのが最適だと思います(私の場合、これはフォームごとに1つに相当します)が、リポジトリクラスは現在アクティブなフォームのセッションにアクセスする必要があります。これをどのように組み込むかわかりません。プレゼンターはシングルトンではないため、これらのリポジトリはウィンザーを介して解決されるという事実があります。

例えば:

public class SomePresenter
{
  private ISomeView view;
  private ISession session;
  private ICustomerRepository customerRepository;
  private IOrderRepository orderRepository;

  public SomePresenter(ISomeView view, ISessionFactory sessionFactory, ICustomerRepository customerRepository, IOrderRepository orderRepository)
  {
    this.view = view;
    this.session = sessionFactory.OpenSession();
    this.customerRepository = customerRepository;
    this.orderRepository = orderRepository;
  }
}

リポジトリはセッションにアクセスする必要があります...Windsorを使用してこれを行うにはどうすればよいですか?プロパティを介してリポジトリに手動でセッションを設定する必要がありますか、それとも私がよく知らない巧妙なウィンザーのトリックがありますか?

4

2 に答える 2

4

ISessionリポジトリの代わりにを単に注入してみませんISessionFactoryか?

これは、別のIoCコンテナであるAutofacで使用する同様のコードです。

containerBuilder
    .Register(c => NHibernateContext.GetSessionFactory().OpenSession())
    .As<ISession>()
    .InstancePerLifetimeScope();

NHibernateを構成し、シングルトンNHibernateContextを保持する唯一の静的クラスはどこにありますか。ISessionFactory

したがって、私のリポジトリ/ルックアップオブジェクトはセッションを要求します:

public MyRepository(ISession session)
{
    this.session = session;
}

次に、私のプレゼンター/ビューモデル/SuperivsingController / Whatever-The-Heck-We're-Calling-It-This-Monthは、リポジトリまたはルックアップオブジェクトを取得します。

public MyPresenter(IWhateverRepository repository)
{
     // Look ma, the repository has an ISession and I'm none the wiser!
}

ウィンザーの場合、私は(私はそのAPIにあまり精通していないので、これを微調整する必要があるかもしれませんが、それはあなたにアイデアを与えるはずです)それは次のようなものになると思います

container.Register(
    Component.For<ISession>
    .UsingFactoryMethod(
        x => x.Resolve<ISessionFactory>().OpenSession())
    .LifeStyle.Transient);

つまり、コンテナに「誰かがISessionを要求したらISessionFactory、セッションを取得して開くこの小さなデリゲートを実行し、そのISessionインスタンスを提供します」と伝えます。

しかし、誰が閉じますISessionか?それはあなた次第です:あなたはISessionそれ自身のDispose()方法でリポジトリを明示的に閉じるようにすることができます。または、コンテナを使用してクローズと破棄を行うこともできます。Autofacでは、これをILifetimeScopeandで行いInstancePerLifetimeScope()ます; ウィンザーでは、ネストされたコンテナーを検索する必要があると思います。子コンテナーを破棄すると、作成されたすべてのコンポーネントも破棄されます。

私の経験では、これは通常、コンテナーが少なくともアプリケーションの「メインフォーム」にリークすることを意味します。フォームを作成するときに、新しいライフタイムスコープ/ネストされたコンテナーが作成され、フォームが表示されます。しかし、このレベルより下の何もコンテナについて知りません。一連のコンポーネントの周りに投げ縄を投げて、「フォームを閉じたら、これらすべてを取り除く」と言うだけです。

(これは、ほとんどのアプリケーションで1つの大きなホーンISessionが使用されるのを防ぐためです。これはASP.NETでは、要求ごとに1つのセッションで正常に機能しますが、Windowsフォームでは、ご存知のように、古いオブジェクトの時限爆弾のようなものです。例外。各「作業単位」(通常、各フォームまたはサービス)には、独自の機能がある方がよいISession。)

ISessionあるいは、各メソッドが渡される必要があるようにリポジトリを設計することもできますが、それは面倒になるようです。

それがあなたにいくつかのアイデアを与えることを願っています。幸運を!

于 2010-08-21T16:30:56.203 に答える
1

プレゼンター/コントローラーごとSessionProviderに個別(DAO)を1つだけ持っていないのはなぜですか?Data Access Objectsモデルには、それぞれからアクセスしますData Access Object

public sealed class SessionProvider
{
        static readonly SessionProvider provider = new SessionProvider();
        private static NHibernate.Cfg.Configuration config;
        private static ISessionFactory factory;
        static ISession session = null;

        /// <summary>
        /// Initializes the <see cref="SessionProvider"/> class.
        /// </summary>
        static SessionProvider() { }

        /// <summary>
        /// Gets the session.
        /// </summary>
        /// <value>The session.</value>
        public static ISession Session
        {
            get
            {
                if (factory == null)
                {
                    config = new NHibernate.Cfg.Configuration();
                    config.Configure();

                    factory = config.BuildSessionFactory();
                }

                if (session == null)
                {                   
                    if (config.Interceptor != null)
                        session = factory.OpenSession(config.Interceptor);
                    else
                        session = factory.OpenSession();
                }

                return session;
            }
        }
    }

public sealed class OrderDataControl
{

        private static ILog log = LogManager.GetLogger(typeof(OrderDataControl));

        private static OrderDataControl orderDataControl;
        private static object lockOrderDataControl = new object();
        /// <summary>
        /// Gets the thread-safe instance
        /// </summary>
        /// <value>The instance.</value>
        public static OrderDataControl Instance
        {
            get
            {
                lock (lockOrderDataControl)
                {
                    if (orderDataControl == null)
                        orderDataControl = new OrderDataControl();
                }
                return orderDataControl;
            }           
        }

        /// <summary>
        /// Gets the session.
        /// </summary>
        /// <value>The session.</value>
        private ISession Session
        {
            get
            {
                return SessionProvider.Session;                
            }
        }


        /// <summary>
        /// Saves the specified contact.
        /// </summary>
        /// <param name="contact">The contact.</param>
        /// <returns></returns>
        public int? Save(OrderItems contact)
        {
            int? retVal = null;
            ITransaction transaction = null;

            try
            {
                transaction = Session.BeginTransaction();
                Session.SaveOrUpdate(contact);

                if (transaction != null && transaction.IsActive)
                    transaction.Commit();
                else
                    Session.Flush();

                retVal = contact.Id;
            }
            catch (Exception ex)
            {
                log.Error(ex);
                if (transaction != null && transaction.IsActive)
                    transaction.Rollback();
                throw;
            }

            return retVal;
        }
于 2010-08-19T13:25:06.350 に答える