을 I는 NHibernate에 위에 구축 지속성 프레임 워크를 가지고 몇 가지 웹 응용 프로그램에서 사용됩니다. 그것은 IRepository
과 IRepository<T>
인터페이스 뒤에 NH 구현을 숨 깁니다. Unity가 제공 한 구체적인 인스턴스를 가지고 있습니다 (따라서 이론적으로 NHibernate를 Entity Framework로 바꾸는 것이 가능합니다).
Unity는 의존성 삽입 그 자체가 아닌 생성자 매개 변수의 전달을 지원하지 않기 때문에 (또는 적어도 사용하고있는 버전은 지원하지 않기 때문에) 현행 NHession을 전달할 수 없습니다. 하지만 나는 UOW의 모든 객체가 같은 Session을 공유하기를 원한다.
난 스레드 단위에 ISession에 대한 액세스를 관리하는 제어 저장소 클래스함으로써이 문제를 해결이 예에서
public static ISession Session
{
get
{
lock (_lockObject)
{
// if a cached session exists, we'll use it
if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY))
{
return (ISession)PersistenceFrameworkContext.Current.Items[NHibernateRepository.SESSION_KEY];
}
else
{
// must create a new session - note we're not caching the new session here... that's the job of
// BeginUnitOfWork().
return _factory.OpenSession(new NHibernateInterceptor());
}
}
}
}
를 PersistenceFrameworkContext.Current.Items
는에 있지 않은 경우 어느 ThreadStatic
저장되는 IList<object>
액세스 웹 컨텍스트에 있거나 웹 컨텍스트에있는 경우 HttpContext.Current.Items
내에 있어야합니다 (스레드 풀 문제를 방지하기 위해). 속성에 대한 첫 번째 호출은 저장된 팩시밀리 인스턴스에서 ISession
을 인스턴스화합니다. 이후 호출은 저장소에서이를 검색합니다. 잠금 기능을 사용하면 물건의 속도가 약간 느려지지만 appdomain-scoped static ISession
인스턴스를 잠그는 것만 큼은 아닙니다.
그렇다면 BeginUnitOfWork
과 EndUnitOfWork
의 UOW를 처리하는 방법이 있습니다. 특별히 중첩 된 UOW를 허용하지 않았습니다. 솔직하게 관리 할 고통 이었기 때문입니다.
public void BeginUnitOfWork()
{
lock (_lockObject)
{
if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY))
EndUnitOfWork();
ISession session = Session;
PersistenceFrameworkContext.Current.Items.Add(SESSION_KEY, session);
}
}
public void EndUnitOfWork()
{
lock (_lockObject)
{
if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY))
{
ISession session = (ISession)PersistenceFrameworkContext.Current.Items[SESSION_KEY];
PersistenceFrameworkContext.Current.Items.Remove(SESSION_KEY);
session.Flush();
session.Dispose();
}
}
}
마지막으로, 방법의 한 쌍의 도메인 형 특정 저장소에 대한 액세스 제공. (여기서, PersistentObject<T>
기본 클래스 제공하는 ID이고, 지지체와 동일)
public IRepository<T> For<T>()
where T : PersistentObject<T>
{
return Container.Resolve<IRepository<T>>();
}
public TRepository For<T, TRepository>()
where T : PersistentObject<T>
where TRepository : IRepository<T>
{
return Container.Resolve<TRepository>();
}
을
따라서 주어진 저장소에 대한 액세스는 패턴입니다.
NHibernateRepository.For<MyDomainType>().Save();
특정 유형의 전문 저장소를 가지고 어디
MyDomainType.Repository.Save();
을 사용할 수 있도록 이상 facaded 그때 IRepository<T>
, 연장 구현 내 IRepository<T>
구현 상속에서 파생 인터페이스를 생성 (즉, 그것이 IRepository<T>
에서 얻을 수있는 것보다 더 많은 필요) 및 도메인 유형 자체에 내가 사용하는 정적 Repository
속성을 재정의 supplyi을 담당 외관 클래스는 [실제 제품에 뭔가 덜 검은 제비 갈매기라고] new
new public static IUserRepository Repository
{
get
{
return MyApplication.Repository.For<User, IUserRepository>();
}
}
(MyApplication
유니티를 통해 Repository
인스턴스를 도메인 클래스 내에서 특정 NHibernate 저장소 구현에 의존하지 않아야합니다.)
이것은 리포지토리 구현을 위해 Unity를 통해 완전히 플러그 가능한 기능을 제공하며, 코드를 통해 저장소로 쉽게 이동할 수 있습니다. 투명하고 스레드 당 ISession
관리.
위의 코드보다 코드가 훨씬 많습니다 (예제 코드를 간단하게 단순화했습니다).하지만 일반적인 생각을 알 수 있습니다. 내 웹 응용 프로그램에서
MyApplication.Repository.BeginUnitOfWork();
User user = User.Repository.FindByEmail("[email protected]");
user.FirstName = "Joe"; // change something
user.LastName = "Bloggs";
// you *can* call User.Repository.Save(user), but you don't need to, because...
MyApplication.Repository.EndUnitOfWork();
// ...causes session flush which saves the changes automatically
, 정말 BeginUnitOfWork
및 EndUnitOfWork
각각 BeginRequest
및 EndRequest
에서 호출되는 세션 당 요청 수 있습니다.
당신이 말한 것처럼 기술적으로는 건축가 적으로 가장 좋은 해결책이 아니더라도 제 질문에 대한 대답입니다. 나는 너를 똑딱 거리고있다. – David