2009-07-13 2 views
9

다음과 같은 클래스가 있습니다.nHibernate로 엔티티 타입에 대한 메소드 무시하기

public class Account 
{ 
    public virtual int Id { get; private set; } 
    public virtual string Username { get; set; } 

    [EditorBrowsable(EditorBrowsableState.Never)] 
    public virtual string Password { get; private set; } 

    public void SetPassword(string password){ ... } 
    public bool CheckPassword(string password) { ... } 
} 

Account 유형을 사용하는 코드에서 직접 사용되는 Password 속성을 원하지 않기 때문에이 방법으로 설정했습니다. 계정 맵은 다음과 같이 보입니다 :

public class AccountMap : ClassMap<Account> 
{ 
    public AccountMap() 
    { 
     Id(x => x.Id); 
     Map(x => x.Username); 
     Map(x => x.Password); 
    } 
} 

실제로 이것을 NHibernate와 함께 사용할 때 InvalidProxyTypeException

NHibernate.InvalidProxyTypeException: The following types may not be used as proxies: 
    Fringine.Users.Account: method SetPassword should be virtual 
    Fringine.Users.Account: method CheckPassword should be virtual 

NHibernate가 게으른 로딩을 지원하기 위해 프록시 클래스를 생성하려고한다는 것을 이해하고 있습니다. 가상으로 예외를 해결하기 위해지도에 Not.LazyLoad()를 추가하는 것으로 메소드를 표시 할 수 있습니다. 그러나 나는 그 중 하나를하고 싶지 않습니다. 게으른로드를 지원하고 싶지만 이러한 메소드가 가상 일 필요가있는 이유를 알지 못합니다.

NHibernate (또는 Castle 내부적으로) 메소드의 내용을 평가하여 사용되는 필드를 판별하고 해당 속성에 대한 지연로드를 최적화합니까? 그렇지 않은 경우, 메소드가 모든 특성이 있고 메소드에 의해 참조 될 때 지연로드 될 경우 메소드가 가상 일 필요가있는 이유는 무엇입니까?

특정 요구 사항을 가상 요구 사항에서 제외 할 수있는 방법이 있습니까?

답변

7

이유는 초기화되지 않습니다 당신의 방법에 필드에 액세스 할 수 있다는 것입니다. 그래서 가장 쉬운 방법은 객체 호출에 엔티티의 내용을로드하는 것입니다 (유일한 예외는 이미 프록시에서 사용할 수있는 ID에 대한 액세스입니다).

따라서 프록시가없는 것처럼 안전하게 메소드를 구현할 수 있습니다. 즉, 메소드가 가상 일 필요가 있다는 트레이드 오프 (나는 동의합니다.)가 완벽하지 않습니다.

클래스 디자인에 문제가 있다고 생각되면 기능을 다른 클래스 (예 : PasswordManager, PasswordValidator 등)로 이동해보십시오. 이 클래스는 Account를 집계하거나 인수로 가져옵니다. 따라서이 클래스가 실제로 해당 속성 중 하나를 호출 할 때만 Account가로드됩니다.

+0

해당 메소드의 필드에 액세스하는 것이 중요하지는 않습니다. 필드가 프록시 속성을 통해 액세스되면 인스턴스를 초기화합니다. 실제로 가상화해야하는 유일한 등록 정보/메소드는 실제로 테이블의 컬럼을 나타내는 것입니다. –

+0

@ 폴 : 아니, 오해. 자신의 메서드에서 * 직접 * 필드에 * 액세스 할 수 있습니다. 이 경우 아무런 문제가 없으며,이 경우 게으른로드에 대해 걱정할 필요가 없습니다. 엔티티의 코드는 완전히 초기화 된 엔티티 내에서 * 항상 * 실행됩니다. 이것은 NH를 더 투명하게 만든다. 실제로 인스턴스의 상태에 의존하지 않는 인스턴스 멤버를 갖는 경우는 드물기 때문에 최적화 할 공간이 매우 제한적입니다. –

+0

아, 나는 오해했습니다. 필드 액세스 보호는 의미가 있습니다. –

0

나는 NHibernate가 POCO를 모든 엔티티에 많이 의존한다는 것을 알아 차렸다. 더 좋든 나쁘 든간에, 나는 누군가 그 대회를 망가뜨린 시나리오를 가로 질러 가지 않았다. 데비 리옹은 explains it in great detail here.(nHibernate 수는 다음 프록시 중 하나를 만들 수 없습니다 때문에 그는, 그래, 당신이 게으른하지로드와 같은 클래스를 표시 할 수 있습니다, 귀하의 지점을 참조합니다. 그러나, 당신은 막히다.)

내가 돈 ' 이것이 도움이되는지는 알지 못하지만, 캐슬 (Castle)이 그렇게하는 방법입니다. 이제 (2.1을 사용하는 경우) you're able to choose which proxy generator to use으로 이동하면 one of the other choices으로 이동하면 필요에 맞는 방식으로 프록시를 생성 할 수 있습니다.

0

클래스 수준에서 지연로드를 비활성화하고 속성별로 속성을 활성화 할 수 있습니다. 지연로드는 종종 수집 연결 관계에 사용됩니다.

public class AccountMap : ClassMap<Account>{   
    public AccountMap() 
    { 
     Not.LazyLoad(); 
     Id(x => x.Id); 
     Map(x => x.Username).LazyLoad(); 
     Map(x => x.Password);   
    } 
} 

또는 개인 필드와 그것을 위해 "필드"전략을 시도 할 수는 :

public class AccountMap : ClassMap<Account>{   
    public AccountMap() 
    { 

     Id(x => x.Id); 
     Map(x => x.Username) 
     Map(x => x.Password).Access.AsCamelCaseField();   
    } 
} 

public class AccountMap : ClassMap<Account>{   
    private string password; 
    public string Password{ get; } 
} 
+0

지도 (x => x.Method())와 유사한 것이 있습니까? 아니오 .LazyLoad()? –

+0

또한이 속성을 사용하여 프록시 생성 ckeck을 비활성화 할 수 있습니다. use_proxy_validator to false – MatthieuGD