2011-05-12 2 views
0

에 아이를 절약됩니다 "객체가 저장되지 않은 과도 인스턴스를 참조 ..."오류가 나는 업데이트 날짜 컬럼에 매핑 된 경우를 부모 (사람 엔티티)와 자식 (사람에 대한 Cascade.None와 PersonTelephone 엔티티)로 매핑 상속 AuditableEntityMapBase 기본 클래스는 다음과 같습니다유창함 NHibernate에 열이 부모

public class PersonTelephoneMap : AuditableEntityMapBase<PersonTelephone> 
{ 
    public PersonTelephoneMap() 
    { 
     Table("pers_PersonTelephone"); 

     Id(x => x.Id, "PersonTelephoneId"); 

     References(x => x.Person, "PersonId") 
      .Cascade.None(); 
     ... 
    } 
} 

을 내가이 사람을 수화하는 것이 가능한 아니다

/// <summary> 
/// Tests nHibernate for concurrency (dirty read) 
/// 1. Telephone1 and Telephone2 entities are loaded in separate sessions 
/// 2. Telephone1 is updated - Telephone2 now has a dirty read 
/// 3. Update Telephone2 and expect NHibernate.StaleObjectStateException error 
/// </summary> 
[Test] 
[ExpectedException("NHibernate.StaleObjectStateException")] //Assert 
public void CanVersionConcurrencyPersonTelephone() 
{ 
    //Arrange 
    const string telNo1 = "911"; 
    const string telNo2 = "999";    
    Person person2 = null; 
    PersonTelephone personTelephone2 = null; 

    var person = CreatePerson(); //Create a new person entity    
    var personManager = new PersonManager();   

    //Act 
    //var person1 = personManager.Read(person.Id); 
    var personTelephone1 = person.Phones[0]; 
    SessionContext.Current.AttachEntity(personTelephone1); 
    SessionContext.Flush(); 

    using (SessionContext.Open()) 
    { 
     person2 = personManager.Read(person.Id); 
     personTelephone2 = person2.Phones[0]; 
     SessionContext.Flush(); 
    } 

    System.Threading.Thread.Sleep(2000); //Arrange for a dirty read by user delay 

    using (SessionContext.Open()) 
    { 
     personTelephone1.Number = telNo1; 
     personManager.UpdateTelephone(personTelephone1); //simulate dirty read for personTelephone2 
     SessionContext.Flush(); 
    } 

    using (SessionContext.Open()) 
    { 
     personTelephone2.Number = telNo2; 
     personManager.UpdateTelephone(personTelephone2); //expect NHibernate.StaleObjectStateException 
     SessionContext.Flush(); 
    } 
} 

:3210

저장 아동 및 다음 시험에서와 같이 플러싱 세션은 부모의 "개체를 세척하기 전에 transient 인스턴스 -SAVE 저장되지 않은 과도 인스턴스를 참조"원인 다음과 같이 개체와는 PersonTelephone 매핑 대신 Cascade.SaveUpdate의 Cascade.SaveUpdate를 사용하여 자 NHibernate 업데이트가 :

나는 또한 처음에는 일을 읽기 전용 방법, 사용하여 시도
References(x => x.Person, "PersonId") 
       .Cascade.SaveUpdate(); 

:

References(x => x.Person, "PersonId") 
        .Cascade.None.ReadOnly(); 

그러나 PersonId가 Null 열이 아니고 읽기 전용이므로 nHibernate 삽입 도중 삽입되지 않았기 때문에 PersonTelephone 테이블에 삽입하는 데 문제가있었습니다.

비관적 잠금이 내 사용자 요구 사항에 맞지 않으며 OptimisticLock.All()에서 성능이 저하됩니다. 또한 Person 엔티티 매핑에 .Cascade.None()을 사용하려고했습니다.

유일한 일은 Person 및 PersonTelephone 테이블에 고유 한 업데이트 필드를 갖는 것입니다. 이 솔루션은 나에게 냄새가 난다. 그런 다음 nHibernate 엔티티 필드에 고유 한 이름을 지정하려고 시도했지만 작동하지 않았습니다. 다른 사람이이 문제를 겪었습니까? 우아한 솔루션이 있습니까?

답변

0

개인 레코드의 "소유권"이 취소되었습니다. PersonTelephones은 Person에 대한 참조를 "소유"합니다. 그러나 계단식 관계는 하향식입니다. PersonTelephone은 사람이 있으면 저장되지만 다른 사람은 저장되지 않습니다.

그래서, 새로운 PersonTelephone을 가진 새로운 Person이 있고 PersonTelephone을 저장하고 있다는 것입니다. Person은 DB에 아직 존재하지 않으며 NH는 PersonTelephone이 저장 될 때 Person을 저장하지 말라는 명령을받습니다. 따라서 할 수있는 유일한 일은 불평입니다.

이 문제를 해결하려면 PersonTelephone이 아닌 Person을 저장하십시오. Person을 삽입하거나 업데이트 한 다음, 연쇄 다운하여 새로운 PersonTelephone을 삽입하거나 업데이트하십시오.

+0

답장을 보내 주셔서 감사합니다. 성능상의 이유로 인하여 사람을 구할 수 없습니다. 또한 우리가 가지고있는 사용자의 수와 함께 StaleObjectStateExceptions가 필요할 때처럼 중앙 테이블을 저장하는 일이 많았습니다. 다른 대안을 알고 있습니까? 고맙습니다. – user750793

+0

그런데 Person 테이블과 PersonTelephone 테이블의 버전 필드 이름이 다르면이 문제가 발생하지 않습니다. 즉,이 경우 Person 테이블이 참조되지 않고 버전 관리가 특정 상황에 계단식으로 연결됨을 의미합니다. 캐스케이드. 아냐. 나에게 이것이 nHibernate 버그라고 생각하니? @ 키스 – user750793

관련 문제