2017-01-27 5 views
0

NHibernate에서 엔티티가 하나의 질의에 의해 지연로드되고 동일한 세션의 두 번째 질의에 의해 eager-loading되도록 요청 된 경우, 두 번째 질의의 반환 된 타입은 항상 프록시입니다 (캐시 된 프록시 첫 번째 쿼리에서). 이것은이 매우 간단하고 영국의 예에서 설명 될 수있다 :이 프로그램에서이전에 같은 세션에서 프록시로드 된 객체를 NHibernate가 완전히로드하도록 할 수 있습니까?

public class CarClassMap : ClassMap<Car> 
{ 
    public CarClassMap() 
    { 
     this.Id(x => x.Id); 
     this.Map(x => x.Model); 
     // note: lazy load by default 
     this.References(x => x.Colour).Column("ColourId").LazyLoad(); 
    } 
} 

public class ColourClassMap : ClassMap<Colour> 
{ 
    public ColourClassMap() 
    { 
     this.Id(x => x.Id); 
     this.Map(x => x.Description);    
    } 
} 

public static void Main() 
{ 
    using (var session = CreateSessionFactory().OpenSession()) 
    { 
     // note: both cars are the same colour in the database 
     var jaguar = session.QueryOver<Car>() 
      .Where(x => x.Id == 1) 
      .FutureValue() 
      .Value;     

     Console.WriteLine("Jaguar colour type=" + jaguar.Colour.GetType()); 

     var aston = 
      session.QueryOver<Car>() 
       .Fetch(x => x.Colour).Eager //note: eager load 
       .Where(x => x.Id == 2) 
       .FutureValue() 
       .Value; 

     Console.WriteLine("Aston Martin colour type=" + aston.Colour.GetType()); 
    } 

    Console.Read(); 
} 

출력은 다음과 같습니다

Jaguar colour type=ColourProxy 
Aston Martin colour type=ColourProxy 

모두 '색상'속성

는 프록시이며, 열심 부하를 요청하는 두 번째 쿼리에도 불구하고. 그러나 단지 열망 부하 쿼리 를 실행할 때 :

public static void Main() 
{ 
    using (var session = CreateSessionFactory().OpenSession()) 
    { 
     var aston = 
      session.QueryOver<Car>() 
       .Fetch(x => x.Colour).Eager 
       .Where(x => x.Id == 2) 
       .FutureValue() 
       .Value; 

     Console.WriteLine("Aston Martin colour type=" + aston.Colour.GetType()); 
    } 

    Console.Read(); 
} 

출력은 다음과 같습니다

Aston Martin colour type=TestApp.Colour 

콘크리트, 기본 유형.

실제 시스템에서는 반환 된 객체가 복잡한 논리를 수행하는 매핑 레이어로 전달됩니다. 이 불일치는 세션에서 이전에 발행 된 쿼리에 따라 속성이 다르게 입력되므로 문제가 발생합니다.

기본적으로 궁금한 점은 프록시를 생성하는 열렬한로드에 대한 요청을 피할 수 있으며 구체적인 유형으로 강제 설정하는 것입니다. 우리는 NHibernate 유틸리티를 사용하여 수동으로 'un-proxy'할 수 있다는 것을 알고 있지만,이 엔티티가 질의 될 때마다 그렇게하지 않아도됩니다. 가능한 경우 클래스 맵에서이를 수행하는 방법을 선호합니다. 아니면 더 좋은 해결책이 있습니까? 감사.

답변

1

기본적으로 NHibernate는 세션이 동일한 엔티티에 대해 리턴하는 인스턴스의 고유성을 보장합니다. 그런 이유로 엔티티에 대한 동일한 세션에 하나가있는 경우 (이전에 완전히 초기화 된)로드 된 지연로드가 이전에로드 된 지연 프록시를 리턴하는 이유입니다.

응용 프로그램의 작동 방식에 따라이를 피하는 데 꽤 어려움을 겪을 수도 있습니다.

회피로드를 피하기 위해 기다리는 동안 세션이 지연 될 수 있지만 보류중인 모든 변경 사항이 취소되고 이전에로드 된 엔터티가 세션에서 분리되는 동안 언로드 된 프록시는 사용할 수 없게 렌더링됩니다.

사전에 참조가있는 경우 엔 Evict이 될 수도 있지만 질문을 읽을 때는 그렇지 않습니다.

나는 프록시 나 기본 엔티티 클래스를 얻는 것을 지원하기 위해 매핑 계층을 조정하려고합니다. 이 question에 관한 것이고 재미있는 답변이 많이 있습니다.

Diego Mijelshon answer'slinked blog의 경우지도 작성 레이어가 항상 구체적인 클래스를 얻을 수 있도록 적합 할 수 있습니다.

그것은 당신이 이미 가지고 있든 프록시를 가지고 있든 상관없이 당신에게 구체적인 인스턴스를 줄 것입니다 당신의 엔티티 클래스에 속성을 추가하는 것으로 구성됩니다. 그는 경고로

public virtual object Actual { get { return this; } } 

이 해킹이다.이 메소드로 얻은 구체적인 인스턴스는 이후에 NHibernate 세션과 함께 사용해서는 안됩니다.

+0

감사합니다.이 링크와 다른 링크가 유용합니다. 매핑 레이어에 몇 가지 견고성을 추가 할 것입니다. –