2010-12-16 3 views
18

Ich versuche, eine Beziehung wie folgt einzurichten. Jeder Meister Artikel hat eine oder mehrere Details Artikel:NHibernate-Konfiguration für unidirektionale Eins-zu-viele-Beziehung

public class Detail { 
    public virtual Guid DetailId { get; set; } 
    public virtual string Name { get; set; } 
} 
public class Master { 
    public virtual Guid MasterId { get; set; } 
    public virtual string Name { get; set; } 
    public virtual IList<Detail> Details { get; set; } 
} 

und Mappings:

public class MasterMap : ClassMap<Master> 
{ 
    public MasterMap() 
    { 
     Id(x => x.MasterId); 
     Map(x => x.Name); 
     HasMany(x => x.Details).Not.KeyNullable.Cascade.All(); 
    } 
} 
public class DetailMap : ClassMap<Detail> 
{ 
    public DetailMap() 
    { 
     Id(x => x.Id); 
     Map(x => x.Name); 
    } 
} 

Die Meister Datenbanktabelle ist:

masterId uniqueidentifier NOT NULL 
name  nvarchar(max) NULL 

und Details ist:

DetailId uniqueidentifier NOT NULL 
name  nvarchar(max) NULL 
MasterId uniqueidentifier NULL 
foreign key (masterId) references [Master] 

Ich weiß nicht wirklich eine Verbindung von Details zu haben, zurück zu Meister - in anderen Worten, Detail Objekte auf ihrem eigenen sind einfach nicht interessant zu meiner Domain-Schicht. Sie werden immer über ihr Master-Objekt zugreifen.

Mit Code wie folgt:

Master mast = new Master 
{ 
    MasterId = new Guid(), 
    Name = "test", 
    Details = new List<Detail> 
    { 
     new Detail { .DetailId = new Guid(), .Name = "Test1" }, 
     new Detail { .DetailId = new Guid(), .Name = "Test1" } 
    } 
}; 

using (transaction == Session.BeginTransaction) 
{ 
    Session.Save(mast); 
    transaction.Commit(); 
} 

Dies funktioniert gut, mit Ausnahme einer verrückten Einschränkung in this post umrissen: NHibernate hat eine INSERT und legt Detail.MasterId als NULL zuerst, dann wird ein UPDATE es auf die echte MasterId.

Wirklich, ich will keine Detaileinträge mit NULL MasterIds, wenn ich das MasterId Feld auf NOT NULL gesetzt habe, wird INSERT to Detail fehlschlagen, weil, wie gesagt, NHibernate versucht, MasterId = NULL zu setzen.

Ich denke, meine Frage dazu läuft darauf hinaus:

Wie kann ich die obige Code Probe bekommen mit meinem vorhandenen Domänenmodell zu arbeiten (zB ohne eine Detail.Master Eigenschaft hinzufügen), und das Detail.MasterId Feld in der Datenbank auf NOT NULL gesetzt?

Gibt es eine Möglichkeit, Nhibernate dazu zu bringen, einfach die richtige MasterId in die anfängliche INSERT zu schreiben, anstatt ein UPDATE danach auszuführen? Gibt es Gründe für diese Designentscheidung? - Ich habe Mühe zu sehen, warum es so gemacht wird.

Antwort

14

Sie können nicht.

Sehr wichtiger Hinweis: die Verbindung von my answer auf der anderen Frage zu zitieren Sie verknüpfen Wenn die <key> Spalt eines NOT NULL deklariert sind <one-to-many> Verein, NHibernate Verletzungen Einschränkung verursachen kann, wenn es erstellt oder aktualisiert die Verband. Um dieses Problem zu vermeiden, müssen Sie eine bidirektionale Verknüpfung mit dem als inverse="true" gekennzeichneten vielwertigen Ende (dem Satz oder der Tasche) verwenden. Weitere Informationen zu bidirektionalen Zuordnungen finden Sie weiter unten in diesem Kapitel.

Edit: wie Hazzik hat zu Recht darauf hingewiesen, dies in NHibernate 3 und höher geändert hat.Die Dokumente haben leider nicht aktualisiert worden ist, so ist hier Hazzik:

[] Wenn Sie setzen inverse="false" und not-null auf <key>, NH3 und oben nur zwei Einsätze INSEAD des Einsatzes Einsatz-Update durchführen.

+0

ich habe gelesen das, aber es hat nicht wirklich etwas erklären (ebenso wenig wie die Diskussion über bidirektionale Verbände verwiesen). Gibt es Gründe für diese Entscheidung? Ist es eine Design-Beschränkung von Nhibernat? Ist es ein Fehler? Als relativ Neuling zu Nhibernate, und nicht zu wissen, die Interna überhaupt, scheint es so, als ob dies möglich sein sollte. – gregmac

+0

Ehrlich gesagt, weiß ich nicht. Es wird vom NHibernate-Team nicht als Fehler eingestuft, es ist nur ein Nebeneffekt davon, wie NHibernate Entitäten persistiert. Ich werde nicht so tun, als wüsste ich die Gründe, aber ich stelle mir vor, dass es etwas damit zu tun hat, unabhängig von Datenbank und Identity Generator zu sein. –

+4

Eigentlich, wenn inverse = "false" und nicht-null auf Schlüssel NH3 und höher wird nur zwei Inserts insert von insert-insert-update – hazzik

4

Der Grund NHibernate es tut so ist, weil:
Wenn es das Detail speichert es nur das Zeug, weiß um das Detail kennt. Daher werden Master-Referenzen, die im Hintergrund passieren, ignoriert. Nur wenn der Master gespeichert wird, sieht er die Beziehung und aktualisiert die Elemente der Sammlung mit der ID des Masters.
Welche ist aus einer objektorientierten Sicht logisch. Aus Sicht des Speicherns ist es jedoch etwas weniger logisch. Ich nehme an, Sie können immer einen Fehlerbericht einreichen oder nachsehen, ob dieser bereits eingereicht wurde und Sie bitten, ihn zu ändern. Aber ich nehme an, dass sie ihre spezifischen (Design/Domain) Gründe haben.

31

NH3 und oben ermöglichen, ohne lästige save null speichern Entitäten bei uni-direktionale Eins-zu-viele-Mapping zu korrigieren - save - update Zyklus, wenn Sie sowohl not-null="true" auf < Schlüssel gesetzt> und inverse="false" auf < One-to viele>

FluentNHibernate Code-snippet für das:

public class MasterMap : ClassMap<Master> 
{ 
    public MasterMap() 
    { 
     Id(x => x.MasterId); 
     Map(x => x.Name); 
     HasMany(x => x.Details) 
      .Not.Inverse()  //these options are very 
      .Not.KeyNullable() //important and work only if set together 
      .Not.KeyUpdate() //to prevent double update 
      .Cascade.All(); 
    } 
} 
+1

Sind Sie sicher, dass es kein wiederholendes Update gibt? Ich richte meine Zuordnung wie beschrieben ein und setzt den Fremdschlüssel korrekt auf der Einfügung (im Gegensatz zum Einfügen von Null), führt dann aber eine zusätzliche Datenbankaktualisierung durch, bei der der Fremdschlüssel auf denselben Wert zurückgesetzt wird, den er in der Einfügung verwendet hat. Sieht so aus, als würde VikciaR es erleben und ein paar andere (basierend auf Upvotes) erleben dasselbe. – Sam

+3

@Sam Set auch '.Not.KeyUpdate()' und Doppel-Update wird – hazzik

+1

Abfragen funktionieren wie erwartet, aber Nhibernate erstellt immer noch eine Spalte auf der db, die NULL Werte erlaubt? Ist das normal? – nemenos