2012-08-23 2 views
1

NHibernate에 거래

그래도해야 할 일

, 할 수있을 것입니다 (MVC + NHibernate에 사이트와 표준 관행으로 보인다) 내가 일하고 프로젝트는 UnitOfWork에는 전체 세션에 대해 정의하고있다

항목 모음을 반복하고 자신의 "로컬"트랜잭션에서 하나씩 차례대로 처리하십시오. 이 같은

뭔가 다음 들어 BeginTransaction 라인은 같은 "외부"세션을 사용하고 있기 때문에

foreach(var item in CollectionOfItems) 
{ 
     using (ITransaction transaction = UnitOfWork.CurrentSession.BeginTransaction()) 
     { 
     //do work on item. rollback on failure, 
     //but it should not affect the other items 
     } 
} 

는하지만이 작동하지 않습니다. 작은 코드 블록에서 트랜잭션을 수행 할 수있는 자체 "로컬"세션을 얻으려면 어떻게해야합니까? 세션이 다음 코드에서 작업 단위로 주입되고 있다고 생각합니다. 컨트롤러가 응답을 반환 그래서 때마다

For<IUnitOfWork>().LifecycleIs(new HybridLifecycle()) 
      .Use<UnitOfWork>(); 

, 세션 :

의 UnitOfWork 클래스는 그것은에 의해 등록되어

private readonly ISessionFactory _sessionFactory; 
    private readonly ITransaction _transaction; 

    public UnitOfWork(ISessionFactory sessionFactory) 
    { 
     _sessionFactory = sessionFactory; 
     CurrentSession = _sessionFactory.OpenSession(); 
     _transaction = CurrentSession.BeginTransaction(); 
    } 

다음 생성자가 : 나는 정확히 어떻게하지만 모르는 내뿜어. 이것은 내가 혼란스러워하는 곳입니다. 나는 항상 모든 것이 전부이거나 아무것도 원하지 않는다.

편집 :

여기

가 NHibernate에 등록 과정에 대한 모든 코드

public NHibernateRegistry() 
    { 
     FluentConfiguration fluentConfig = Fluently.Configure() 
      .Database(
       MsSqlConfiguration.MsSql2008.ShowSql().ConnectionString(x => x.FromConnectionStringWithKey("conn"))) 
      .ProxyFactoryFactory(typeof (ProxyFactoryFactory).AssemblyQualifiedName) 
      .Mappings(m => m.FluentMappings.AddFromAssemblyOf<CustomerMap>()); 


     Configuration configuration = fluentConfig.BuildConfiguration(); 

     ConfigureNhibernateValidator(configuration); 

     ISessionFactory sessionFactory = fluentConfig.BuildSessionFactory(); 

     For<Configuration>().LifecycleIs(new HybridLifecycle()).Singleton().Use(configuration); 

     For<ISessionFactory>().LifecycleIs(new HybridLifecycle()).Singleton().Use(sessionFactory); 

     For<ISession>().LifecycleIs(new HybridLifecycle()) 
      .Use(x => x.GetInstance<ISessionFactory>().OpenSession()); 

     For<IUnitOfWork>().LifecycleIs(new HybridLifecycle()) 
      .Use<UnitOfWork>(); 

     For<ITssPrincipal>().HybridHttpOrThreadLocalScoped().Use(container => BuildUserInstanceFromThreadCurrentPrincipal()); 

     Scan(x => 
     { 
      x.TheCallingAssembly(); 
      x.WithDefaultConventions(); 
     }); 
    } 

편집 : 아래의 예에서 DI 문제의 예를 , 당신은 볼 그쪽으로 RepoA는 RepoB와 모두 DI'd한다 StructureMap에서 제공하는 UnitOfWork를 얻습니다.

public RepoA(IUnitOfWork unitOfWork, ITssPrincipal principal, 
    IRepoB repoB) 
{ 
} 

public RepoB(IUnitOfWork unitOfWork, ITssPrincipal principal) 
{ 
} 

내가 RepoA의 기능에 새로운 세션을 생성하더라도, repoB는 여전히 원래의 UnitOfWork 세션을 사용하는 것입니다

그것은 그것을 만드는 의존성 주입 컨테이너로 StructureMap를 사용하여 MVC 웹 사이트처럼 보이는
+1

foreach 루프를 수행하는 클래스에서 세션 팩토리를 사용할 수 있습니까? UnitOfWork.CurrentSession을 사용하는 대신 루프를 통해 팩토리를 사용하여 새 세션을 만든 다음 해당 세션에 대해 BeginTransaction()을 호출 할 수 있습니까? – jkriddle

+0

주 세션 설정 방법을 표시하는 코드가 추가되었습니다. 어떻게 든 내 루프에서 fluentConfig.BuildSessionFactory()를 사용할 수 있습니까? – getit

+1

Randy의 답변은 옳았지만 마지막 의견에 추가하십시오. 항상 세션은 저렴하지만 세션 * 공장은 비쌉니다.그러므로 항상 새로운 공장을 만드는 것을 피하십시오 (그리고 결코 필요없는 의존성 주입을 사용하여). – jkriddle

답변

3

아주 쉽게 당신이 원하는 것을 할 수 있습니다.

두 가지 옵션이 있지만 가장 쉬운 방법은 Structure Map에서 ISession의 새 인스턴스를 요청하는 것입니다. 그러면 UnitOfWork에서 사용하는 것과는 다른 새로운 Session이 반환됩니다. 여기

은 예입니다 :

var session = StructureMap.ObjectFactory.GetInstance<ISession>(); 

using (var tx = session.BeginTransaction()) 
{ 
    try 
    { 
     // Do your work here 

     tx.Commit(); 
    } 
    catch (Exception) 
    { 
     tx.Rollback(); 

     throw; 
    } 
} 

당신이 DI 컨테이너를 사용하고 있기 때문에, 당신은 또한 StructureMap의 의존성 주입을 활용하고 새로운 ISession 등 컨트롤러/클래스/저장소의 생성자에 주입 가질 수있는 방법을 사용하면 StructureMap의 ObjectFactory.GetInstance <>() 메서드를 호출 할 필요가 없습니다.

+0

으로 OP를 업데이트했습니다. 감사합니다. 이것은 내가 필요로하는 것에 가까이 다가 가고 있지만 여전히 문제가있다. 호출되는 저장소 함수는 여전히 원래 UnitOfWork 세션에 대한 참조를 가지고있다. 위의 컨텍스트 내에서 repo 호출을 새로 생성 된 세션을 사용하는 방법이 있습니까? – getit

+0

@getit 새로 생성 된 NHibernate 세션을 필요로하는 추가 의존성이 있다면, 컬렉션에있는 항목 당 새로운 UnitOfWork를 원하는 것처럼 들린다. 이 시점에서 응용 프로그램의 아키텍처가 실제로 가능한지 아닌지에 관해 논합니다. 일부 UnitOfWork 구현체는 중첩 된 UnitOfWorks를 지원할 수 있습니다. 응용 프로그램이 중첩 된 UnitOfWorks를 지원할 수 없다면 창의력을 발휘해야합니다. 한 가지 옵션은 초기 UnitOfWork를 닫거나 커밋하고 컬렉션의 항목 당 새 UnitOfWork를 수동으로 시작하고 커밋하는 것입니다. –