2009-07-13 11 views
9

Ho una classe di qualcosa di simile a questo:Ignorando metodi su tipi di entità con 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) { ... } 
} 

ho impostato su questo senso dal momento che non voglio più la proprietà Password utilizzata direttamente nel codice che utilizza il tipo Account. La mappa account simile a questa:

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

Quando Io in realtà uso questo con NHibernate ottengo un 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 

Capisco che NHibernate sta cercando di creare una classe proxy per supportare il caricamento pigro e che Posso contrassegnare i metodi come virtuali aggiungere un Not.LazyLoad() alla mappa per risolvere l'eccezione. Ma - Non voglio fare nessuna di quelle. Voglio supportare il caricamento lento, ma non vedo perché questi metodi debbano essere virtuali.

NHibernate (o Castle internamente) valuta il contenuto del metodo per determinare quali campi vengono utilizzati e ottimizzare il carico lento per tali proprietà? In caso contrario, perché il metodo deve essere virtuale se tutte le proprietà sono e saranno pigre-caricate quando vengono referenziate dal metodo.

Esiste un modo per escludere determinati metodi dal requisito virtuale?

risposta

7

Il motivo è che si potrebbe accedere ai campi nei vostri metodi, che non verranno inizializzate. Quindi il modo più semplice è caricare il contenuto dell'entità su qualsiasi chiamata all'oggetto (l'unica eccezione è l'accesso all'ID, che è già disponibile nel proxy).

Così puoi tranquillamente implementare i tuoi metodi come se non ci fossero proxy, con il compromesso che il metodo deve essere virtuale (che - concordo - non è perfetto).

Se pensi che questo sia un problema per il tuo progetto di classe, prova a spostare la funzionalità in un'altra classe (ad esempio PasswordManager, PasswordValidator ecc.). Questa classe aggregherà l'account o lo prenderà come argomento, quindi l'account verrà caricato solo quando questa classe chiama effettivamente una delle sue proprietà.

+0

Non sono sicuro che importi se accedo a un campo con questi metodi. Quando si accede al campo tramite la sua proprietà proxy, inizializzerà l'istanza. Le sole proprietà/metodi che devono effettivamente essere virtualizzati sono quelle che rappresentano effettivamente le colonne nella tabella. –

+0

@Paul: No, fraintendimenti. Puoi * accedere * ai campi * direttamente * nei tuoi metodi. Non c'è niente di sbagliato in questo, non è necessario preoccuparsi del caricamento lento in questo caso. Il codice nelle tue entità è * sempre * eseguito all'interno di un'entità completamente inizializzata. Questo rende l'NH più trasparente. In realtà è raro avere membri di istanze che non dipendono dallo stato dell'istanza, quindi c'è uno spazio molto limitato per l'ottimizzazione. –

+0

Ah, ho frainteso. La protezione dell'accesso al campo ha senso. –

0

Ho notato che NHibernate fa molto affidamento su POCO per tutte le sue entità. Nel bene o nel male, non ho incontrato nessuno scenario in cui qualcuno abbia violato quella convenzione. Davy Brion explains it in great detail here.(Si fa riferimento al punto che, sì, è possibile contrassegnare le classi il carico non pigro. Ma, dal momento che NHibernate allora non creerà nessuna delle vostre deleghe, sei bloccato.)

I don' so se questo è utile, ma è così che Castle lo fa. Ora che (se si utilizza 2.1) you're able to choose which proxy generator to use, passare a one of the other choices potrebbe consentire di generare proxy in base alle proprie esigenze.

0

È possibile disattivare il caricamento lazy a livello di classe e attivarlo nella proprietà per base di proprietà, il carico lento viene spesso utilizzato per le relazioni di raccolta-associazione.

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

Oppure si può provare con un campo privato e una strategia di "campo" per esso:

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

C'è qualcosa di simile a Map (x => x.Method()) .Not.LazyLoad()? –

+0

puoi anche disattivare la generazione del proxy ckeck con questa proprietà: use_proxy_validator su false – MatthieuGD

Problemi correlati