2010-12-14 5 views
8

나는 스스로 해결책을 제시하는 동안이 질문을 던질 것이라고 생각했다.NHibernate와 Autofac으로 여러 데이터베이스 관리하기

대량의 응용 프로그램을 구축 한 후에 추가 데이터베이스 (2 개는 총망라 가능)에 대한 읽기/쓰기를 지원하는 마지막 요구 사항이 있습니다. DI/IoC 구성 요소를 공급하는 Autofac과 함께 NHibernate를 사용하여 애플리케이션을 구축했습니다. FWIW, 이것은 ASP.NET MVC 2 응용 프로그램에 있습니다.

NHibernate 세션을 사용하는 일반 저장소 클래스가 있습니다. 이론적으로 두 번째 데이터베이스에이 일반 저장소 (IRepository<>)를 계속 사용할 수 있습니다.이 세션에 전달 된 세션이 적절한 SessionFactory에서 생성 된 것이라면 맞습니까?

글쎄, 앱이 시작될 때 Autofac이하는 일을합니다. 세션과의 SessionFactory에 관해서, 나는 상태 모듈이 있습니다

builder.Register(c => c.Resolve<ISessionFactory>().OpenSession()) 
    .InstancePerMatchingLifetimeScope(WebLifetime.Request) 
    .OnActivated(e => 
    { 
     e.Context.Resolve<TransactionManager>().CurrentTransaction = ((ISession)e.Instance).BeginTransaction(); 
    }); 

builder.Register(c => ConfigureNHibernate()) 
    .SingleInstance(); 
기본 SessionFactory를 반환 ConfigureNHibernate은()처럼 보인다

: 현재

private ISessionFactory ConfigureNHibernate() 
{ 
    Configuration cfg = new Configuration().Configure(); 
    cfg.AddAssembly(typeof(Entity).Assembly); 
    return cfg.Configure().BuildSessionFactory(); 
} 

, 이것은 단지로 제한 하나의 데이터베이스. 다른 NHib 시나리오에서, 나는 분리 된 SessionFactory의 인스턴스를 해쉬로 갈아서 필요할 때마다 검색 할 것이다. 우리가 메이저 릴리스에 상당히 가까워 질 때 모든 것을 다시 설계해야하는 것을 원하지 않습니다. 따라서 적어도 두 개의 SessionFactories를 독립적으로 구성 할 수 있도록 위의 메소드를 수정해야한다고 생각합니다. 내 회색 영역은 올바른 저장소가 특정 저장소와 함께 사용되도록 지정하는 방법 (또는 적어도 두 번째 데이터베이스에 특정한 엔터티)을 지정하는 방법입니다.

이런 식으로 IoC 컨테이너와 NHibernate를 사용하는 동안 누구나이 시나리오를 경험 한 적이 있습니까?

내가 구성 파일 경로를 취하는 GetSessionFactory 방법을 스텁 한 편집은 HttpRuntime.Cache에서 일치하는 SessionFactory에의 실존에 대한 검사는,이 아직 존재하지 않는 경우 새로운 인스턴스를 생성하고, 해당 SessionFactory를 반환합니다. 이제는 적절한 설정 경로를 지정하는 방법과시기를 Autofac에 알려주는 방법을 알아야합니다. (빌리의 2006 포스트 here에서 많이 차용)와 같은 새로운 방법은 같습니다 당신이 각 데이터베이스에 갈 엔티티의 다른 유형을 원하는 있으리라 믿고있어

private ISessionFactory GetSessionFactory(string sessionFactoryConfigPath) 
    { 
     Configuration cfg = null; 
     var sessionFactory = (ISessionFactory)HttpRuntime.Cache.Get(sessionFactoryConfigPath); 

     if (sessionFactory == null) 
     { 
      if (!File.Exists(sessionFactoryConfigPath)) 
       throw new FileNotFoundException("The nhibernate configuration file at '" + sessionFactoryConfigPath + "' could not be found."); 

      cfg = new Configuration().Configure(sessionFactoryConfigPath); 
      sessionFactory = cfg.BuildSessionFactory(); 

      if (sessionFactory == null) 
      { 
       throw new Exception("cfg.BuildSessionFactory() returned null."); 
      } 

      HttpRuntime.Cache.Add(sessionFactoryConfigPath, sessionFactory, null, DateTime.Now.AddDays(7), TimeSpan.Zero, System.Web.Caching.CacheItemPriority.High, null); 
     } 

     return sessionFactory; 
    } 
+1

캐시에 세션 팩토리를 저장하는 것은 좋지 않습니다. 그것은 단지 사라지고 재창조 될 수있는 것이 아닙니다. –

+0

알아. 실제로는 캐시 된 객체의 수명을 관리해야합니다. Billy의 예제는 실제로이 단계를 더 진행하고 캐싱 관련 사항을 처리하는 Singleton 범위의 SessionManager 클래스를 만들었습니다. 나는 그것을 결국 바보 취급하려고 했으므로 Autofac이 자체 (매우 우아한) 범위 지정 메커니즘을 통해 관리 할 수있게 할 수있었습니다. – nkirkes

답변

11

; 각 데이터베이스에 같은 종류의 엔터티를 유지하려면 AutofacContrib.Multitenant를 확인하십시오. 이 시나리오 도움을 줄 수

두 성분은 다음과 같습니다이 하나

먼저 이름이 지정된 서비스를 사용하여 두 개의 서로 다른 데이터베이스를 참조하십시오. 나는 그들을 "db1""db2 "이라고 부를 것이다.당신이 생성자의 매개 변수로 ISession를 받아들이는 형식 NHibernateRepository<T>이 있으리라 믿고, 이제

builder.Register(c => ConfigureDb1()) 
    .Named<ISessionFactory>("db1") 
    .SingleInstance(); 

builder.Register(c => c.ResolveNamed<ISessionFactory>("db1").OpenSession()) 
    .Named<ISession>("db1") 
    .InstancePerLifetimeScope(); 

// Same for "db2" and so-on. 

을하고 그 다음 세션에 모든 방법까지 데이터베이스에 관련된 모든 구성 요소는 이름으로 등록받을 엔티티 유형이 주어지면 "db1" 또는 "db2"을 반환하는 함수 WhichDatabase(Type entityType)을 작성할 수 있습니다.

우리는 ResolvedParameter을 사용하여 엔티티 유형에 따라 세션을 동적으로 선택합니다.

builder.RegisterGeneric(typeof(NHibernateRepository<>)) 
    .As(typeof(IRepository<>)) 
    .WithParameter(new ResolvedParameter(
     (pi, c) => pi.ParameterType == typeof(ISession), 
     (pi, c) => c.ResolveNamed<ISession>(
      WhichDatabase(pi.Member.DeclaringType.GetGenericArguments()[0]))); 

(경고 - 컴파일 및 구글 크롬에서 테스트))

지금, IRepository<MyEntity>를 해결하는 것은 적절한 세션을 선택하며, 세션은 게으르게 초기화 제대로 Autofac에 의해 배치하는 것입니다.

물론 트랜잭션 관리에 대해 신중하게 생각해야합니다.

희망이 트릭을! NB

+1

야, 너 그거야. 너무 굉장해! 나는 시나리오를 위해 약간의 조정을했고 업데이트 된 Autofac 소스를 좀 더 파헤쳐서 무슨 일이 벌어지는 지 이해할 수 있었지만 지옥 예, 그렇기 때문에 나는 이것을 좋아합니다! 감사 니콜라스! – nkirkes

+0

듣기 좋음 - 천만에! –