0

NHibernate에서 영감을 얻은 DAL 리펙토링 연옥의 일부로 리포지토리 패턴을 사용하여 NHibernate를 UI 레이어에서 유지할 수 있습니다. 다음은 저장소의 Load 메서드 예제입니다.NHibernate : 리포지토리에서 완전히로드 된 인스턴스를 반환하기위한 패턴

public StoredWill Load(int id) 
{ 
    StoredWill storedWill; 
    using (ISession session = NHibernateSessionFactory.OpenSession()) 
    { 
    storedWill = session.Load<StoredWill>(id); 
    } 
    return storedWill; 
} 

저는 웹 사이트에서 세션이 무엇인지 알지 못합니다.

물론 위의 메서드가 StoredWill을로드하지 않기 때문에 초기화가 지연되는 경우가 발생하기 시작합니다. 프록시 만 반환합니다. 프록시의 속성에 접근 할 때, 여러분은 Session의 범위 내에서 더 길기 때문에 예외가 발생합니다. 나는 무슨 일이 일어나고 있는지 깨달았을 때 크게 웃었다.

나는 함께이 문제를 해결 한 :

public StoredWill Load(int id) 
{ 
    StoredWill storedWill; 
    using (ISession session = NHibernateSessionFactory.OpenSession()) 
    { 
    storedWill = session.Load<StoredWill>(id); 
    string iReallyCouldntCareLess = storedWill.TestatorLastName; 
    } 
    return storedWill; 
} 

하지만 모두 약간의 바보을 보인다. 누구보다 약간 더 우아한 패턴을 사용합니까?

당신을 사랑해. ncommon framework 밖으로

데이비드

답변

4

종속성 주입을 사용하고 생성자를 통해 저장소 클래스에 ISession을 전달합니다. 이는 여러 저장소가 동일한 트랜잭션에 참여할 수있게하는 유일한 방법입니다.

웹 사이트는 트랜잭션 경계가 정의 된 곳이기 때문에 ISession에 대한 지식이 있어야합니다. 세션 당 요청 패턴을 사용하여 ISession이 HttpRequest 모듈 또는 Global.asax에서만 참조되도록 할 수 있습니다. 또는 프레임 워크를 사용하거나 NHibernate를 포용하고 페이지에서 트랜잭션을 제어 할 수 있습니다. 당신이 만일 Session.load() 대신()에 Session.get 의를 사용하고 있다는 문제

+0

나는 정말로 혼란 스럽다. 저장소 패턴의 요점은 UI 계층에서 ORM implmementation을 숨기는 것이라고 생각했습니다. – David

+0

세부 사항을 숨기지 만, 참여하는 작업 단위를 저장소에 알릴 필요가 있습니다. 작업 단위 컨테이너로 ISession을 사용하거나 자체 작업 단위 구현에서 랩핑 할 수 있습니다. –

1

확인; 이런 종류의 작업에 완벽하게 맞는 전략을 가져 오는 것이 좋습니다. 이것이 구현되는 방법에 대한 자세한 내용은 author's blog에서 확인할 수 있습니다.

세션 사용량이 약간 부족하다는 점에 유의해야합니다. 세션의 수명주기를 실제로 제어해야합니다 (프런트 엔드에 따라 컨트롤러 또는 httpmodule 수준에서 말하기). 각 저장소 작업에 대한 새로운 세션을 여는 것은 nhibernate 세계에서 주요한 반 패턴이다.

+0

반전 계기가되는 자체 ISession을 인스턴스화하는 저장소 작업에 대해. 당신은 정교 할 수 있습니까? IS 세션이 싸다고 생각 했나요? – David

+0

아, 알다시피, 당신은 더러운 검사를 잃게됩니다. – David

+0

@David : 그 이상으로, 정말로 ... 첫 번째 레벨 캐시 (ID 맵), 지연된 쓰기 작업, 느린 로딩 (찾은 것처럼) 등을 잃게됩니다. – DanP

1
public StoredWill Load(int id) 
{ 
    StoredWill storedWill; 
    using (ISession session = NHibernateSessionFactory.OpenSession()) 
    { 
    storedWill = session.Load<StoredWill>(id); 
    // force an eager load within the session 
    NHibernateUtil.Initialize(storedWill.TestatorLastName); 
    } 
    return storedWill; 
} 
+0

무례한 점은 없지만 원래 게시 한 내용을 어떻게 개선 했습니까? – David

+1

NHibernateUtil.Initialize (storedWill)를 의미합니까? 적어도 그러면 당신은 임의의 자산을 부르지 않을 것입니다. – David

+1

모든 필드 또는 하나의 필드를 미리로드하려면 분명하지 않았습니다. 문자열을 정의 할 필요가 없으므로 "바보"가 적기 때문에 개선 된 기능입니다. 원하는 결과와 영속 클래스의 구조에 따라 NHibernate 매핑에 'default-lazy = "false"'를 추가하는 것도 흥미로울 것입니다. – anthony

0

부분이다.

두 가지에 대한 자세한 설명은 Ayende Rahien - The difference between Get, Load and querying by id을 참조하십시오.

Session.Load()을 호출하면 nhibernate가 사용자가 제공 한 ID의 프록시 개체를 생성하게됩니다. 이 작업을 수행 할 때 nhibernate는 실제로 데이터베이스를 호출하여 데이터를 검색하지 않습니다. 즉, Session.Load() 데이터베이스에 존재하지 않는 것이 있으면 Exception을 발생시킵니다. 객체에 액세스하기 전에 세션을 닫으므로 proxys 세션이 닫혀 있기 때문에 데이터에 액세스 할 수 없습니다.

간단한 수정은 Session.Get()을 사용하도록 코드를 변경하는 것입니다.이렇게하면 데이터베이스에서 StoredWill 클래스를로드하고 개체에 필요한 데이터를 채 웁니다. 그러나 내부 클래스 나 컬렉션이 객체 내부에있는 경우 객체에 대한 프록시를 만들뿐입니다. 한 번에 모든 것을 가져와야하는 경우, 필요한 부품을 열심히로드하거나 예상을 사용하기 위해 많은 쿼리 메커니즘 중 하나를 사용할 수 있습니다.

이 정보가 도움이 되었으면 좋겠다.

+0

당신의 대답이 기술 된 문제를 해결할지라도, 디자인의 더 깊은 문제가 있습니다. DanP의 답변과 자세한 내용은 다음 의견을 읽으십시오. – David