2009-06-03 16 views
11

In einem typischen Modell, in dem Sie über mehrere untergeordnete Elemente und ein untergeordnetes Element verfügen, die nur ein übergeordnetes Element haben können, verwalten Sie das Hinzufügen von untergeordneten Elementen. Ich habe diesen Ansatz verwendet;Best Practice für die Verarbeitung von NHibernate-Eltern-Kind-Sammlungen

public class Parent 
{ 
    public Parent() 
    { 
     Children = new List<Child>(); 
    } 

    public IList<Child> Children 
    { 
     get; 
     private set; 
    } 
} 

public class Child 
{ 
    public Parent Parent 
    { 
     get; 
     set; 
    } 
} 

var child = new Child(); 
var parent = new Parent(); 
parent.Children.Add(child); 
child.Parent = parent; 

Problem ist, dass überall ich ein neues Kind hinzufügen möchte ich habe zu erinnern, einen Verweis auf hinzuzufügen, sowohl das Kind und Eltern und seine ein wenig Schmerzen. Ich könnte einfach eine AddChild-Methode zur Elternklasse hinzufügen und diese für das Hinzufügen von Kindern verantwortlich machen - das Problem besteht nun darin, dass es zwei Möglichkeiten gibt, ein Kind hinzuzufügen, über die Children-Eigenschaft und die Methode. Ist das also eine bessere Lösung?

public class Parent 
{ 
    public Parent() 
    { 
     children = new List<Child>(); 
    } 

    private IList<Child> children 
    { 
     get; 
     private set; 
    } 

    public IEnumerable<Child> Children 
    { 
     get 
     { 
      return children; 
     } 
    } 

    public void AddChild(Child child) 
    { 
     children.Add(child); 
     child.Parent = this; 
    } 
} 

Gibt es Hinweise für Best Practices zu diesem Thema und was tun Sie?

Antwort

2

ich es so, außer, dass ich Eigenschaft nicht für den privaten Gebrauch Liste

private IList<Child> _children 
public IEnumerable<Child> Children 
{ 
    get 
    { 
     return children; 
    } 
} 
+2

Dies ist eine gute Lösung, aber mit einem Nachteil, dass, wenn der Verbraucher die Children zu IList er auf die Liste zugreifen und ändern könnte .. eine andere Möglichkeit könnte ReadOnlyCollection <> verwenden –

10

Dies ist überhaupt kein NHibernate-Problem.

Sie sollten die AddChild-Methode implementieren. Die Klassen sind für ihre Konsistenz verantwortlich, also sollten sie nichts aussetzen, was nicht verfügbar sein sollte. Zum Beispiel sollte die (veränderbare) Kinderliste ausgeblendet werden. Ein IEnumerable ist eine gute Idee.

Ihr zweiter Code ist ein guter Ausgangspunkt. Sie benötigen wahrscheinlich noch weitere Methoden wie RemoveChild oder CoundChildren.

+0

Sprechen wir das zweite Beispiel meine einzige Sorge ist, wie dies mit Linq zu NHibernate funktionieren kann. Da die tatsächlich gemappte Eigenschaft jetzt privat ist, würde ich annehmen, dass sie nicht sichtbar ist. Irgendwelche Gedanken? – Gareth

+0

Sie können in Ihrer Zuordnung angeben, dass NHibernte das Feld anstelle der Eigenschaft verwenden soll, wenn Sie einen Wert festlegen. (Sehen Sie sich zum Beispiel das Zugriffsattribut an). –

+0

Ja, was ich wollte, war, dass, wenn Linq zu NHibernate fertig ist, wie können Sie es verwenden, wenn das Feld privat ist und der öffentliche Zugriff nur einen Verweis auf die ursprüngliche Sammlung zurückgibt. Z.B. session.Linq (). Wo (x => x.Children.Name.Equals ("Jonnie")) – Gareth

5

Ich mache es wie folgt aus:

public class Parent 
{ 
    private ISet<Child> _children = new HashedSet<Child>(); 

    public ReadOnlyCollection<Child> Children 
    { 
     get{ return new List(_children).AsReadOnly(); } 
    } 

    public void AddChild(Child c) 
    { 
     if(c != null && !_children.Contains (d)) 
     { 
      c.Parent = this; 
      _children.Add (c); 
     } 
    } 
} 

So in der Tat, das ist ein bisschen was Stefan auch sagt. Ich enthülle nur eine readonly-Kopie der Children-Liste, so dass Sie leicht über die Kinder eines Elternteils iterieren können und die Anzahl der Kinder, die der Elternteil hat, erhalten. Hinzufügen und Entfernen von untergeordneten Elementen zum übergeordneten Element muss mithilfe der AddChild & RemoveChild-Elementmethoden erfolgen.

+1

Ein Set wird keine Duplikate hinzufügen Sie müssen also nicht prüfen, ob das Kind bereits existiert. –

-1

Ich mag nicht all die zusätzlichen AddXXX() und RemoveXXX() Methoden überstopfen meine Entität Schnittstellen. Stattdessen habe ich eine benutzerdefinierte Liste, die Ereignisse auslöst, wenn die Methoden Add() und Remove() aufgerufen werden.

Die Verknüpfung geschieht dann in den Event-Handler:

public class Course() 
{ 
    public Course() 
    { 
    this.Topics = new EntityList<Topic>(); 
    this.Topics.AddItem += new AddItemEventHandler<Topic>(Topic_AddItem); 
    this.Topics.RemoveItem += new RemoveItemEventHandler<Topic>(Topic_RemoveItem); 
    } 

    public EntityList<Topic> Topics { get; private set; } 

    private void Topic_AddItem(Topic item, object args) 
    { 
    // Replace with your linking code: 
    EntityLinker.Link(this).With(item, args); 
    } 

    private void Topic_RemoveItem(Topic item, object args) 
    { 
    // Replace with your unlinking code: 
    EntityLinker.Unlink(this).From(item, args); 
    } 
} 
+4

Ich mag diesen Ansatz nicht. :) Hinter den Kulissen läuft viel "Magie". Ich erinnere mich, dass Ayende einmal diesen Ansatz auch verwendete (in NHibernate Generics, wenn ich mich nicht irre), aber jetzt sehe ich nicht, dass er diesen Ansatz nicht mehr verwendet. Ich finde nur, dass die "Link" -Logik zu viel versteckt ist. Daneben sehe ich Addxxxx Methoden zu meinen Entitäten nicht als Unordnung der Schnittstelle hinzufügen. Außerdem finde ich es besser, da es expliziter ist. –

+0

Das sieht für mich nicht gut aus. – UpTheCreek

1

Ich bin mit öffentlichen IEnumerable mit Hinzufügen | Entferne Methoden Ansatz.

Allerdings mag ich es nicht sehr, weil es nicht intuitiv ist und die Klassendefinition polemisiert.

Ich frage mich, warum Leute nicht CustomCollection verwenden, wo sie hinzufügen, entfernen, ersetzen Funktionen ?? (wie es überall in MS-Code getan wird) ????

0

Ich unterstütze die akzeptierte Lösung für diese Frage, aber die vorgestellte Lösung ist nicht vollständig, da die Verwendung privater Felder einige zusätzliche Konfiguration in den Mappern erfordert. Zum Wohl des anderen, ist die folgende die komplette Lösung:

public partial class Test 
{ 
    private readonly IList<Child> children = new List<Child>(); 
    public virtual IEnumerable<Child> Children 
    { 
     get 
     { 
      return children; 
     } 
    } 
} 

Beachten Sie, dass die öffentlich ausgesetzte Sammlung virtuell sein muss für NHibernate es zu benutzen.Ich mache es auch gern zu einem schreibgeschützten Feld, das beim Erstellen der Klasse initialisiert wird, um sicherzustellen, dass es in allen Szenarien existiert. Hier ist der zugehörige Mapper:

public class TestMap : ClassMap<Test> 
{ 
    ... 
    HasMany(s => s.Children).Access.CamelCaseField(); 
} 

Die Access Eigenschaft NHibernate teilt dem privaten Bereich zu verwenden, wenn Werte in das Modell abzubilden. Es gibt auch andere Optionen für die Access-Eigenschaft, die die Verwendung verschiedener Benennungskonfigurationen ermöglichen.

0

Wenn Sie einen Fremdschlüssel in Ihrer DB haben und Sie Identity (SQL Server) verwenden, um Ihre Primärschlüssel zu generieren, gehen Sie zu NEED der Backlink vom Kind zum Eltern. Sonst wird sich die Einfügung über child beschweren, da Nhibernate für die Eltern-ID etwas hin und her tun muss, aber es hat es noch nicht getan.

Was wir getan haben, um Backlinks loszuwerden: Verwenden Sie den NHibernate HiLo Generator. Auf diese Weise verfügt NHibernate immer über die IDs, die zum Einfügen der übergeordneten/untergeordneten Beziehungen erforderlich sind.

< 3!

Verwandte Themen