2009-03-14 16 views
10

Domänenmodell, an dem ich arbeite, hat Stammaggregat und untergeordnete Entitäten. So etwas wie den folgenden Code:Was ist die beste Vorgehensweise für schreibgeschützte Listen in NHibernate?

class Order 
{ 
    IList<OrderLine> Lines {get;set;} 
} 

class OrderLine 
{ 
} 

Jetzt möchte ich meine Bestellung Linien zu steuern. So etwas Ähnliches:

class Order 
{ 
    OrderLine[] Lines {get;} 

    void AddLine(OrderLine line); 
} 

Zu dieser Zeit verwenden wir das folgende Muster:

class Order 
{ 
    private IList<OrderLine> lines = new List<OrderLine>(); 
    OrderLine[] Lines {get {return this.lines;}} 

    void AddLine(OrderLine line) 
    { 
     this.orders.Add(line); 
    { 
} 

NHibernate direkt an den Linien Feld abgebildet wird.

Jetzt Fragen ...

  • Was tun Sie in solchen Situationen üben?
  • Haben Methoden jemand Gebrauch: öffentliche IEnumerable GetLines()
  • Was werden Sie als Rückgabetyp für Eigenschaft verwenden? Kann ReadOnlyCollection oder IEnumerable sein;
  • Vielleicht ist dies nicht der beste Ort, um zu fragen? Schlage bitte vor.

Update: Es scheint, IEnumerable gewinnt, jedoch immer noch Lösung ist nicht perfekt ...

Antwort

9

Das Muster Ich benutze ist:

class Order 
{ 
    private List<OrderLine> lines = new List<OrderLine>(); 

    IEnumerable<OrderLine> Lines { get { return this.lines; } } 

    void AddLine(OrderLine line) 
    { 
     this.orders.Add(line); 
    } 
} 

Wenn Sie NET 3.5 verwenden Sie alle Suche erhalten Funktionalität, die Sie für IEnumerable mit LINQ benötigen, und Sie verbergen Ihre Sammlung Implementierung.

Das Problem bei der Rückkehr Orderline [] ist, dass Ihre Sammlung extern zB geändert werden kann:

Order.Lines[0] = new OrderLine(). 
+0

In Bezug auf "Order.Lines [0] = new Orderline();" es kann nicht. Jedes Mal, wenn Sie auf die Zeilen zugreifen, wird eine neue Kopie des Arrays ausgegeben (das gefällt mir aber nicht ...). IEnumerable hat keine Listenfunktionalität, ich meine Count, Zugriff nach Index. Natürlich deckt LINQ dies ab. Vielen Dank! –

+0

Hier können Sie weiterhin die Eigenschaft Linien in eine Liste umwandeln und die Sammlung auf diese Weise ändern ... –

+2

Ja, aber Sie müssen das Casting durchführen. Es geht nicht so sehr um Schutz, sondern darum, zu zeigen, was man mit der Sammlung machen darf. Sie können this.lines.AsReadonly() zurückgeben, wenn Sie diese zusätzliche Sicherheit wünschen. – gcores

3

ich aussetzen Sammlungen wie Readonlycollection und ADDx und RemovEx Methoden für die Pflege der Sammlungen verwenden. Wir sind gerade auf 3.5 umgestiegen und ich denke darüber nach, IEnumerable stattdessen verfügbar zu machen. In den meisten Fällen mit NHibernate hat das Kind einen Verweis auf das übergeordnete Belichtung so hinzufügen und Methoden entfernen können Sie diese Beziehung aufrecht zu erhalten:

public void AddPlayer(Player player) 
    { 
     player.Company = this; 
     this._Players.Add(player); 
    } 

    public void RemovePlayer(Player player) 
    { 
     player.Company = null; 
     this._Players.Remove(player); 
    } 
+0

Yeh, scheint IEnumerable Beats ReadOnlyCollection ... ReadOnlyCollection machen API verwirrend. Es hat immer noch Add-Methode, die Ausnahme in Runtime werfen wird ... –

+1

Mike - Ich denke, dass Sie sich darin täuschen. Zurückgeben einer Liste .AsReadOnly() stellt eine Add-Methode bereit, aber ReadOnlyCollection nicht. ReadOnlyCollection ist in System.Collections.ObjectModel, so dass es oft übersehen wird. –

+0

Lustig, ja das ist wahr ..Ich habe es übersehen. Vielen Dank. –

1

Wenn ich eine Liste bin auszusetzen, die nicht geändert werden soll, dann verwende ich IEnumerable und Ausbeute. Ich finde es umständlich, ReadOnlyCollections in Verbindung mit NHiberante zu verwenden.

Mit diesem Ansatz haben Sie immer noch das private Linienfeld, das über NHibernate zugeordnet und aufgefüllt wird; Der öffentliche Zugriff auf die Sammlung erfolgt jedoch über Iteratoren. Mit dieser Lines-Eigenschaft können Sie der zugrunde liegenden Liste weder hinzufügen noch sie entfernen.

Zum Beispiel:

public IEnumerable<OrderLine> Lines { 
    get { 
     foreach (OrderLine aline in lines) { 
      yield return aline; 
     } 
    } 
} 
+0

Warum nicht einfach "Rückleitungen"? Sie schützen vor dem Gießen? Solution with yield bedeutet, dass Count() foreach benötigt und alle backed ites lädt (im Falle von Lazy Load). –

+0

Mit IEnumerable in Kombination mit dem Ertrag können Sie die Sammlung durchgehen, ohne Elemente hinzufügen/entfernen zu können. –

+0

Nun, IEnumerable selbst würde auch verhindern, dass Sie Elemente hinzufügen/entfernen - also ein 'public IEnumerable Lines {get {return lines; }} sollte ausreichen. – Dav

14

Ich mache es wie folgt aus:

public class Order 
{ 
     private ISet<OrderLine> _orderLines = new HashedSet<OrderLine>(); 

     public ReadOnlyCollection<OrderLine> OrderLines 
     { 
      get { return new List<OrderLine>(_orderLines).AsReadOnly(); } 
     } 

     public void AddOrderLine(OrderLine ol) 
     { 
      ... 
     } 
} 

Dann offcourse, in der Abbildung wird NHibernate das _orderLines Feld verwenden gesagt:

<set name="OrderLine" access="field.camelcase-underscore" ... > 
... 
</set> 
+0

Mit Ihrem Code wird folgender Code fehlschlagen: order.OrderLines! = Order.OrderLines; Ich bin mir nicht sicher, ob das schlecht ist oder nicht ... Wie auch immer danke. –

+0

Das ist egal imho, da sollte man es nicht so vergleichen :) –

+0

Gute Lösung. Das hat mir sehr geholfen. Vielen Dank! – CalebHC

0

Ich habe mehrere Tage damit verbracht, in NHibernate den besten Ansatz für readonly Listen zu suchen. Diese Diskussion hat mir sehr geholfen, diejenige zu bilden, die zu unserem Projekt passt.

Es ist ein Ansatz, den ich begann zu verwenden:

  1. Backing Felder zum Speichern von Sammlungen verwendet werden
  2. IEnumerable < T> verwendet wird, Sammlungen zu belichten Kunden zu zwingen, verwendet AddLine() und RemoveLine() -Methoden .
  3. Der ReadOnlyCollection-Typ wird zusätzlich zu IEnumerable verwendet.

Code:

public class Order 
{ 
    private readonly IList<OrderLine> lines = new List<OrderLine>(); 

    public virtual IEnumerable<OrderLine> Lines 
    { 
     get 
     { 
      return new ReadOnlyCollection<OrderLine>(lines); 
     } 
    } 

    public void AddLine(OrderLine line) 
    { 
     if (!lines.Contains(line)) 
     { 
      this.lines.Add(line); 
      line.Order = this; 
     } 
    } 

    public void RemoveLine(OrderLine line) 
    { 
     if (lines.Contains(line)) 
     { 
      this.lines.Remove(line); 
      line.Order = null; 
     } 
    } 
} 

public class OrderLine 
{ 
    public Order Order { get; set; } 
} 
Verwandte Themen