2011-07-01 3 views
1

는 문서에 따르면, 만일 Session.load (ID)는NHibernate 세션로드 메소드를 사용하면 프록시를 초기화하지 않고 엔티티의 ID에 액세스 할 수 있습니까?

초기화되지 않은 프록시이며, 실제로 데이터베이스에 접속하지 않는다 객체 ... 나는이 같은

이 크다을 반환 시나리오 (내가 db에 있다는 것을 알고)와 나중에 (동일한 세션 내에서) 엔티티의 ID에 액세스하고 일반적으로 ID에만 액세스하고 프록시를 초기화하지 않는 시나리오를로드해야합니다. 프록시의 ID에만 액세스하면 초기화 할 필요가 없다고 생각됩니다. 적어도 그것은 내가 바라는 것이지만 그렇게 할 수는 없다.

[Test] 
public void Accessing_loaded_entity_id_should_not_initialize_the_proxy() 
{ 
    // Arrange 
    var repo = new NHRepository<Order>(); 
    var order = new OrderBuilder().Build(); 

    repo.Save(order); 
    repo.Flush(); 
    repo.Clear(); 

    // Act 
    var fromDb = repo.Load(order.ID); 

    // Assert 
    Assert.AreEqual(order.ID, fromDb.ID); 
    Assert.IsFalse(NHibernateUtil.IsInitialized(fromDb)); 
} 

이 테스트는 여기에 실패 :

는 기본적으로 내가 전달하는 다음과 같은 시험을 얻으려고

Assert.IsFalse (NHibernateUtil.IsInitialized (fromDb));

<id name="id" access="field"> 
    <generator class="hilo"> 
     <param name="column">OrderNextHi</param> 
     <param name="max_lo">100</param> 
    </generator> 
</id> 

가 여기 내 기본 엔터티 형식입니다 :

업데이트 다음은 ID의 내 HBM 매핑입니다. 나는이 문제를 오래전에 카피하고 그 안에 많은 생각을 넣지 않았으므로 여기에 문제가 있다고 생각하고있다.

public abstract class SingleIdentityDomainEntity<T> where T : SingleIdentityDomainEntity<T> 
{ 
    private readonly int id; 
    private int? _oldHashCode; 

    protected SingleIdentityDomainEntity() 
    { 
     this.id = 0;  
    } 

    public virtual int ID 
    { 
     get { return this.id; } 
    } 

    public override bool Equals(object obj) 
    { 
     var other = obj as T; 
     if (other == null) 
      return false; 

     // handle the case of comparing two NEW objects 
     if (other.IsTransient() && this.IsTransient()) 
      return ReferenceEquals(other, this); 

     return other.ID.Equals(this.ID); 
    } 

    /// <summary> 
    /// Transient objects are not associated with an item already in storage. 
    /// </summary> 
    public virtual bool IsTransient() 
    { 
     return this.ID == 0; 
    } 

    /// <summary> 
    /// Must be provided to properly compare two objects 
    /// </summary> 
    public override int GetHashCode() 
    { 
     // Once we have a hash code we'll never change it 
     if (_oldHashCode.HasValue) 
      return _oldHashCode.Value; 

     // When this instance is transient, we use the base GetHashCode() 
     // and remember it, so an instance can NEVER change its hash code. 
     if (this.IsTransient()) 
     { 
      _oldHashCode = base.GetHashCode(); 
      return _oldHashCode.Value; 
     } 

     return this.ID.GetHashCode(); 
    } 
} 
+0

어설 션이 실제로 db에서로드를 강제 실행합니까? 당신은 SQL을 볼 수 있습니까? –

+0

@Mark, 두 어설 션을 var i = fromDb.ID로 바꿉니다. SQL 프로파일 러에서 select sql 문이 생성되었다는 것을 확인할 수있었습니다. –

+0

ID 속성 뒤에 코드를 게시하고 주문에서 ID proprty에 대한 매핑을 게시 할 수 있습니까? –

답변

0

내가 저장소의 구현을 모르지만 나는 당신의 문제가있는 생각 : 나를 어떻게 생각하는지 보자

repo.Clear(); 

라인. 나는 당신의 세션을 지우는 것 같아요 (모든 캐시 값은 축출되었습니다).

+0

Clear() 메서드가 캐시 된 값을 모두 내보내는 이유는이 메서드를 호출하는 이유입니다. 나는 Load를 호출 할 때 순서 obj가 세션에 존재하기를 원하지 않는다. 내가 repo에서로드 할 때, 나는 실제로 프록시를 원한다. 그렇다면 내 희망은 단지 프록시에서 ID를 얻으려고하면 프록시가 초기화되지 않고 데이터베이스가 손상되지 않는다는 것입니다. 분명히 프록시에 다른 메서드를 호출하면 DB 히트가 예상되지만 ID는 이미로드 메서드에 매개 변수로 사용했기 때문에 이미 프록시에로드되어야합니다. 말이 돼? –

+0

nhibernate 문서에서 : ** Hibernate는 데이터베이스로부터 얼마나 많은 양을로드하고 얼마나 많은 SQL SELECT를 사용할 것인가? 이는 가져 오기 전략에 따라 다릅니다. 이는 19.1 절. "가져 오기 전략"에서 설명합니다. ** 이것은 매핑에서 가져 오기 전략을 설정해야 함을 의미합니다. – Peter

관련 문제