2009-04-21 17 views
12

Ho un'entità mappata, Materia, che ha un componente mappato, Lesione.Mappatura del componente NHibernate - Componente nullo

L'unica proprietà sulla ferita è DateOfInjury che è un datetime nullable.

Quando recupero l'argomento, se DateOfInjury è nullo, il componente è nullo.

Così qualcosa del genere. Lesione.DateOfInjury getterà.

Qualcuno potrebbe spiegare se sto facendo qualcosa di ovvio per causare questo comportamento?

Mi sarei aspettato che il componente Injury fosse inizializzato da nHibernate come oggetto e che la proprietà DateOfinjury fosse nullo.

Sarebbe più flessibile, penserei?

+2

Potrebbe essere utile sfruttare il sistema di intercettazione/evento NHibernate per chiamare un inizializzatore PostLoad sull'oggetto Materia per inizializzare un membro Injury se è nullo. Questo fa sanguinare un po 'il livello aziendale, ma può essere minimizzato (può rendere l'inizializzatore un metodo statico interno su Materia, per esempio) – fostandy

risposta

9

Penso che sia il comportamento predefinito per una mappatura dei componenti. I documenti NHibernate per componente dicono che se tutti gli elementi del componente sono nulli, il componente stesso sarà nullo.

Se si dispone di una singola proprietà nel componente, potrebbe essere opportuno mapparla come proprietà DateTime nullable nella classe Materia.

+0

Abbastanza soddisfacente, il componente avrà in definitiva più proprietà. Penso che sarebbe bello se il componente tornasse non nullo, se tutte le proprietà sono dati opzionali, l'id deve fare un controllo nullo per tener conto del comportamento di tipo nhibner. –

+0

Sono d'accordo, quel comportamento è un po 'strano. Mi sarei aspettato che facesse quello che stavi dicendo. Credo che abbia senso, salva Hibernate dalla creazione di un oggetto extra quando non c'è nulla da mettere dentro. –

5

Ho anche avuto lo stesso problema di aspettare che NHibernate inizializzi il mio componente anche se tutti i suoi membri sono nulli nel DB. La mia motivazione alla base di questa implementazione è stata quella di spostare la maggior parte della logica riguardante il mio componente nel componente, non dovendone considerare nulla o no.

Grazie a questo post, la mia ricerca di una spiegazione del perché i miei test di unità non riuscivano per tutti i valori nulli all'interno del componente era breve. Ho fissato questo pezzo nel puzzle estendendo l'auto-proprietà della mia classe di un componente ArrivalDay e assegnando un esempio fresco me stesso quando viene assegnato null:

private ArrivalDay _arrivalDay; 
public ArrivalDay ArrivalDay 
{ 
    get { return _arrivalDay; } 
    set { _arrivalDay = value ?? new ArrivalDay(); } 
}

Questo funziona come un fascino e significa molto poco in testa alla classe che contiene .

+5

Unico problema qui: questo crea problemi a NHibernate durante il monitoraggio dei componenti. Otterrai un 'oggetto fa riferimento a un'istanza transitoria non salvata' una volta che proverai a svuotare l'istanza – Tigraine

2

ho risolto questo con l'aggiunta di questa proprietà per la mia classe di componente

public virtual bool _LoadAlways { get { return true; } set { } } 
+0

questo non sembra funzionare per me, deve essere mappata anche questa proprietà? – sawe

1

Questa è una soluzione tecnicamente praticabile. L'ho testato con persistenza e non ha prodotto problemi relativi ai transienti.

protected internal virtual Injury NullableInjury {get;set;} 
public virtual Injury Injury 
{ 
    get{return NullableInjury ?? (NullableInjury = new Injury()); 
} 

In Nhibate mappa il tuo componente al NullableInjury. Questa soluzione consente di persistere senza il problema transitorio riportato nella soluzione @Oliver.

0

https://stackoverflow.com/a/11187173/206297 non ha funzionato per me, ma la costruzione su di esso:

public class Injury 
{ 
    // ... 
    private bool dummyFieldToLoadEmptyComponent { get; set; } 
} 

public class MatterMap : ClassMap<Matter> 
{ 
    // ... 
    Component(x => x.Injury, m => 
    { 
     // ... 
     m.Map(Reveal.Member<Injury>("dummyFieldToLoadEmptyComponent")).Formula("1=1").ReadOnly(); 
    }); 
} 

Il bit Reveal.Member è solo quello di mappare un campo privato in Fluent NHibernate. Vogliamo il campo privato perché non vogliamo che la proprietà venga esposta come parte della nostra interfaccia pubblica al componente. Vedi https://github.com/jagregory/fluent-nhibernate/wiki/Mapping-private-properties.Se non ti dispiace averlo pubblico, è possibile utilizzare la mappatura meno prolissa di:

m.Map(x => x.DummyFieldToLoadEmptyComponent).Formula("1=1").ReadOnly(); 

La Formula parte è perché in realtà non vogliamo una colonna nel nostro DB per questo. NHibernate eseguirà quella formula quando caricherà il componente e verrà sempre valutata come vera. Ho scelto 1 = 1 come immagino sia ragionevolmente cross-DB.

Indubbiamente un hack, ma sembra funzionare finora per il caricamento di componenti vuoti e non ha causato errori durante la persistenza. Usare comunque con discrezione.

+0

"Ho scelto 1 = 1 come immagino che sia ragionevolmente cross-DB" - si scopre che è una cattiva ipotesi, dato che non funziona su SQL Server. L'uso di '.Formula (" 1 ")' funziona su SQL Server. – ngm

Problemi correlati