11

簡単な質問です。

Castle.Windsor、nHibernate、および ASP.NET MVC で UnitOfWork を使用するにはどうすればよいですか?

次に、拡張された詳細について説明します。パターンを理解するための私の探求では、具体的にインストールする必要がある方法に関して、UnitOfWorkと組み合わせて直接的な例を使用するものに出くわすのに苦労しています。Castle.Windsor

ここまでが私の理解です。

IUnitOfWork

  • IUnitOfWorkインターフェイスは、パターンを宣言するために使用されます
  • UnitOfWorkクラスはCommitRollbackトランザクション、および公開する必要がありますSession

そうは言っても、ここに私のIUnitOfWork. (私は使用していますFluent nHibernate

public interface IUnitOfWork : IDisposable
{
    ISession Session { get; private set; }
    void Rollback();
    void Commit();
}

これが私のCastle.Windsorコンテナブートストラップ(ASP.NET MVC)です

public class WindsorContainerFactory
{
    private static Castle.Windsor.IWindsorContainer container;
    private static readonly object SyncObject = new object();

    public static Castle.Windsor.IWindsorContainer Current()
    {
        if (container == null)
        {
            lock (SyncObject)
            {
                if (container == null)
                {
                    container = new Castle.Windsor.WindsorContainer();

                    container.Install(new Installers.SessionInstaller());
                    container.Install(new Installers.RepositoryInstaller());
                    container.Install(new Installers.ProviderInstaller());
                    container.Install(new Installers.ControllerInstaller());
                }
            }

        }

        return container;
    }
}

だから今、私のGlobal.asaxファイルには、次のものがあります...

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        // Register the Windsor Container
        ControllerBuilder.Current
            .SetControllerFactory(new Containers.WindsorControllerFactory());
    }

リポジトリ

ISessionこれで、をリポジトリに渡す必要があることがわかりました。では、と仮定しましょうIMembershipRepository

class MembershipRepository : IMembershipRepository
{
   private readonly ISession session;
   public MembershipRepository(ISession session)
   {
      this.session = session;
   }

   public Member RetrieveMember(string email)
   {
      return session.Query<Member>().SingleOrDefault( i => i.Email == email );
   }
}

だから私は今、混乱しています。この方法を使用するISessionと、 が適切に破棄されず、UnitOfWorkが使用されることはありません。

Web リクエスト レベルに移行する必要があるとの連絡を受けましたがUnitOfWork、実際にこれを行う方法を説明するものは見つかりません。私はいかなる種類の a も使用しませんServiceLocator(私が試したとき、これも悪い習慣だと言われました...)。

混乱 -- はどのようUnitOfWorkに作成されるのですか?

一般的に、私はこれを理解していません。UnitOfWork私の考えでは、コンストラクターに 渡し始めようと考えていRepositoryましたが、それが Web リクエストに含まれる必要がある場合、この 2 つがどこに関係しているのかわかりません。

さらなるコード

これは、質問に対して正しい情報を提供しないという習慣があるように見えるため、明確にするための追加のコードです。

インストーラー

public class ControllerInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            AllTypes.FromThisAssembly()
            .BasedOn<IController>()
            .Configure(c => c.LifeStyle.Transient));
    }
}

public class ProviderInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component
            .For<Membership.IFormsAuthenticationProvider>()
            .ImplementedBy<Membership.FormsAuthenticationProvider>()
            .LifeStyle.Singleton
        );
    }
}

public class RepositoryInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component
            .For<Membership.IMembershipRepository>()
            .ImplementedBy<Membership.MembershipRepository>()
            .LifeStyle.Transient
        );

        container.Register(
            Component
            .For<Characters.ICharacterRepository>()
            .ImplementedBy<Characters.CharacterRepository>()
            .LifeStyle.Transient
        );
    }
}

public class SessionInstaller : Castle.MicroKernel.Registration.IWindsorInstaller
{
    private static ISessionFactory factory;
    private static readonly object SyncObject = new object();

    public void Install(Castle.Windsor.IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<ISessionFactory>()
                .UsingFactoryMethod(SessionFactoryFactory)
                .LifeStyle.Singleton
            );

        container.Register(
            Component.For<ISession>()
            .UsingFactoryMethod(c => SessionFactoryFactory().OpenSession())
            .LifeStyle.Transient
        );
    }

    private static ISessionFactory SessionFactoryFactory()
    {
        if (factory == null)
            lock (SyncObject)
                if (factory == null)
                    factory = Persistence.SessionFactory.Map(System.Web.Configuration.WebConfigurationManager.ConnectionStrings["Remote"].ConnectionString);
        return factory;
    }
}

UnitOfWork

これが私のUnitOfWorkクラスの逐語です。

public class UnitOfWork : IUnitOfWork
{
    private readonly ISessionFactory sessionFactory;
    private readonly ITransaction transaction;

    public UnitOfWork(ISessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
        Session = this.sessionFactory.OpenSession();
        transaction = Session.BeginTransaction();
    }

    public ISession Session { get; private set; }

    public void Dispose()
    {
        Session.Close();
        Session = null;
    }

    public void Rollback()
    {
        if (transaction.IsActive)
            transaction.Rollback();
    }

    public void Commit()
    {
        if (transaction.IsActive)
            transaction.Commit();
    }
}
4

2 に答える 2

5

NHセッションはすでに作業単位ですhttp://nhforge.org/wikis/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.aspx

ですから、なぜこれをさらに抽象化する必要があるのか​​わかりません。(この回答を読んでいる人が私が喜んで聞く理由を知っているなら、私はあなたがそうする必要がある理由を正直に聞いたことがありません...)

リクエストごとに単純なセッションを実装します。Windsorを使用したことがないので、どうすればよいかわかりませんが、StructureMapを使用するとかなり簡単になります。

構造マップファクトリをラップしてセッションファクトリを保持し、必要に応じてセッションをリポジトリに挿入します。

    public static class IoC
    {
        static IoC()
        {
            ObjectFactory.Initialize(x =>
            {
                x.UseDefaultStructureMapConfigFile = false;

                // NHibernate ISessionFactory
                x.ForSingletonOf<ISessionFactory>()
                 .Use(new SessionFactoryManager().CreateSessionFactory());

                // NHibernate ISession
                x.For().HybridHttpOrThreadLocalScoped()
                 .Use(s => s.GetInstance<ISessionFactory>().OpenSession());

                x.Scan(s => s.AssembliesFromApplicationBaseDirectory());
            });

            ObjectFactory.AssertConfigurationIsValid();
        }

        public static T Resolve<T>()
        {
            return ObjectFactory.GetInstance<T>();
        }

        public static void ReleaseAndDisposeAllHttpScopedObjects()
        {
            ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
        }
    }

Request_Endのglobal.asaxファイルで、ReleaseAndDisposeAllHttpScopedObjects()メソッドを呼び出します。

        protected void Application_EndRequest(object sender, EventArgs e)
        {
            IoC.ReleaseAndDisposeAllHttpScopedObjects();
        }

したがって、最初のリポジトリを呼び出すとセッションが開かれ、リクエストが終了するとセッションは破棄されます。リポジトリには、ISessionを取得してプロパティに割り当てるコンストラクタがあります。次に、次のようにリポジトリを解決します。

var productRepository = IoC.Resolve<IProductRepository>();

お役に立てば幸いです。それを行うには他にも多くの方法があります、これは私のために働くものです。

于 2010-12-21T13:19:15.643 に答える
0

図書館の用語があなたが精通している用語と一致しないのは、言語/インピーダンスの不一致の問題ですか?

私もこの[流暢な]無邪気さにはかなり慣れていないので、私はまだそれを理解しようとしていますが、私の見解はこれです:

通常、ISessionをアプリケーションセッションに関連付けます(たとえば、Webアプリの場合は、セッションの作成をApplication_Startイベントに関連付け、アプリがシャットダウンしたときに破棄することを検討します-正常にまたはそうでない場合)。アプリのスコープがなくなると、リポジトリもなくなります。

UnitOfWorkは、トランザクションをラップ/抽象化する方法にすぎません。更新中に実行するアクションが複数あり、一貫性を保つには、トランザクションを順番に、正常に完了する必要があります。些細なビジネスルール以上のものをデータの作成、分析、または変換に適用する場合など...

これは、流暢なスタイルでISessionとUnitOfWorkを使用する例を提供するブログ投稿へのリンクです。 http://blog.bobcravens.com/2010/06/the-repository-pattern-with-linq-to-fluent-nhibernate-and-mysql/#comments

編集:強調するために、リポジトリに対するすべての操作に作業単位を使用する必要はないと思います。UnitOfWorkが本当に必要になるのは、トランザクションが唯一の合理的な選択である場合だけですが、私もこれから始めています。

于 2010-12-24T11:51:48.610 に答える