2009-04-21 3 views
12

Ich habe eine zugeordnete Entität, Materie, die eine zugeordnete Komponente, Injury hat.NHibernate Komponente Mapping - Null-Komponente

Die einzige Eigenschaft der Verletzung ist DateOfInjury, die eine Nullzeit datetime ist.

Wenn ich die Angelegenheit abrufe, wenn die DateOfInjury null ist, ist die Komponente null.

So etwas wie diese Angelegenheit.Injury.DateOfInjury wird werfen.

Könnte jemand erklären, ob ich etwas Offensichtliches mache, um dieses Verhalten zu verursachen?

Ich hätte erwartet, dass die Injury-Komponente von nHibernate als ein Objekt initialisiert wird und dass die DateOfinjury-Eigenschaft null ist.

Dies wäre flexibler, würde ich denken?

+2

Möglicherweise lohnt es sich, das NHibernate Interceptor/Event-System zu verwenden, um einen PostLoad-Initialisierer für Ihr Matter-Objekt aufzurufen, um ein Injury-Member zu initialisieren, wenn es null ist. Dies blutet zwar in Ihrer Business-Schicht ein, aber es kann minimiert werden (kann den Initialisierer zum Beispiel zu einer internen statischen Methode auf Matter machen). – fostandy

Antwort

9

Ich denke, das ist das Standardverhalten für eine Komponentenzuordnung. Die NHibernate-Dokumentation für eine Komponente besagt, dass, wenn alle Elemente der Komponente null sind, die Komponente selbst null ist.

Wenn Sie nur eine einzige Eigenschaft in der Komponente haben, kann es sinnvoll sein, sie nur als nullable DateTime-Eigenschaft für die Matter-Klasse zuzuordnen.

+0

Gut genug, die Komponente wird letztendlich mehr Eigenschaften haben. Ich denke, es wäre schön, wenn die Komponente nicht-null zurückkommen würde, wenn alle Eigenschaften optionale Daten sind, ID muss eine Null-Prüfung, um für nhibernates Verhalten gerecht zu werden. –

+0

Ich stimme zu, dieses Verhalten ist ein wenig seltsam. Ich hätte erwartet, dass es das tut, was du gesagt hast. Ich denke, es macht Sinn, es bewahrt Hibernate davor, ein zusätzliches Objekt zu erstellen, wenn nichts darin enthalten ist. –

5

Ich lief auch in das gleiche Problem von NHibernate zu erwarten, meine Komponente zu initialisieren, auch wenn alle seine Mitglieder in der DB null sind. Meine Motivation hinter dieser Implementierung war, so viel Logik in Bezug auf meine Komponente in die Komponente zu verschieben, dass ich mich nicht darum kümmern muss, dass sie null ist oder nicht.

Dank dieser Post meine Suche nach einer Erklärung, warum meine Komponententests für alle Null-Werte innerhalb der Komponente fehlgeschlagen waren, war kurz. Ich reparierte dieses Stück im Puzzle durch die Auto-Eigenschaft meiner Komponentenklasse ArrivalDay erstreckt und eine neue Instanz selbst zuweisen, wenn null zugeordnet:

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

Dies wirkt wie ein Zauber und bedeutet sehr wenig Aufwand auf der enthaltenden Klasse .

+5

Nur Problem hier: Dies verursacht Probleme für NHibernate beim Verfolgen der Komponenten. Sie erhalten ein "Objekt verweist auf eine nicht gespeicherte transiente Instanz", sobald Sie versuchen, die Instanz zu leeren – Tigraine

2

Ich habe dieses Problem gelöst, indem Sie diese Eigenschaft meine Komponentenklasse

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

das scheint nicht für mich arbeiten, muss diese Eigenschaft auch zugeordnet werden? – sawe

1

Dies ist eine technisch machbare Lösung. Ich habe es mit Ausdauer getestet und keine transienten Probleme verursacht.

In Nhibernate Karte Ihre Komponente auf die NullableInjury. Mit dieser Lösung können Sie ohne das in der @Oliver-Lösung gemeldete vorübergehende Problem fortfahren.

0

https://stackoverflow.com/a/11187173/206297 nicht für mich arbeiten, sondern baut darauf:

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(); 
    }); 
} 

Das Reveal.Member Bit ist nur ein privates Feld in Fluent NHibernate abzubilden. Wir möchten, dass das Feld privat ist, da diese Eigenschaft nicht als Teil unserer öffentlichen Schnittstelle zur Komponente verfügbar sein soll. Siehe https://github.com/jagregory/fluent-nhibernate/wiki/Mapping-private-properties.Wenn Sie nichts dagegen haben es öffentlich ist, können Sie die weniger ausführliche Kartierung verwenden:

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

Der Formula Teil ist, weil wir nicht wirklich eine Spalte in unserer DB für diese wollen. NHibernate führt diese Formel beim Laden der Komponente aus und wird immer als wahr ausgewertet. Ich habe 1 = 1 gewählt, da ich mir vorstellen kann, dass das vernünftig über DB ist.

Zweifellos ein Hack, scheint aber bisher zum Laden leerer Komponenten zu funktionieren und hat beim Fortbestehen keine Fehler verursacht. Verwenden Sie jedoch mit Diskretion.

+0

"Ich wählte 1 = 1, da ich mir vorstellen kann, dass das vernünftig über DB verläuft" - stellt sich heraus, dass dies eine schlechte Annahme ist, da es auf SQL Server nicht funktioniert. Die Verwendung von '.Formula (" 1 ") funktioniert auf SQL Server. – ngm