5

In unserer mehrschichtigen Geschäftsanwendung haben wir ObservableCollections Self-Tracking Entities, die von Serviceaufrufen zurückgegeben werden.Wie verfolgen Sie Objekte, die in CRUD-Szenarien aus einer ObservableCollection gelöscht wurden?

Die Idee ist, wir in der Lage sein, Entitäten zu erhalten, hinzufügen, aktualisieren und entfernen sie von der Sammlung Client-Seite, und senden Sie diese Änderungen an die Server-Seite, wo sie in der Datenbank gespeichert werden.

Self-Tracking-Entitäten, wie ihr Name vermuten lässt, verfolgen ihren Zustand selbst. Wenn ein neues STE erstellt wird, hat es den hinzugefügten Status, wenn Sie eine Eigenschaft ändern, legt es den Status Modified fest, es kann auch gelöschten Status haben, aber dieser Status wird nicht festgelegt, wenn die Entität von ObservableCollection entfernt wird (natürlich). Wenn Sie dieses Verhalten wollen, müssen Sie es selbst programmieren.

In meiner aktuellen Implementierung, wenn ein Unternehmen aus den ObservableCollection entfernt wird, ich halte es in einem Schatten Sammlung, so dass, wenn die ObservableCollection zurück an den Server gesendet, sie entlang die gelöschten Objekte senden kann, so Entity Framework kennt um sie zu löschen.

Etwas entlang der Linien von:

protected IDictionary<int, IList> DeletedCollections = new Dictionary<int, IList>(); 

protected void SubscribeDeletionHandler<TEntity>(ObservableCollection<TEntity> collection) 
{ 
    var deletedEntities = new List<TEntity>(); 
    DeletedCollections[collection.GetHashCode()] = deletedEntities; 

    collection.CollectionChanged += (o, a) => 
     { 
      if (a.OldItems != null) 
      { 
       deletedEntities.AddRange(a.OldItems.Cast<TEntity>()); 
      } 
     }; 
} 

Nun, wenn der Benutzer seine Änderungen an den Server zu speichern entscheidet, kann ich die Liste der entfernten Einzelteile erhalten, und senden Sie sie an:

ObservableCollection<Customer> customers = MyServiceProxy.GetCustomers(); 

customers.RemoveAt(0); 

MyServiceProxy.UpdateCustomers(customers); 

An dieser Stelle wird die Methode meine Shadow-Sammlung überprüfen, wenn Elemente entfernt wurden, und sie an die Serverseite senden.

Dieser Ansatz funktioniert gut, bis Sie beginnen, über den Lebenszyklus dieser Schattenkollektionen nachzudenken. Wenn der ObservableCollection Müll gesammelt wird, gibt es keine Möglichkeit zu wissen, dass wir die Schattensammlung aus unserem Wörterbuch entfernen müssen.

Ich kam mit einer komplizierten Lösung, die in diesem Fall grundsätzlich manuelle Speicherverwaltung macht. Ich behalte eine WeakReference an die ObservableCollection und alle paar Sekunden überprüfe ich, ob die Referenz inaktiv ist, in welchem ​​Fall ich die Schattensammlung entfernen.

Aber das scheint eine schreckliche Lösung ... Ich hoffe, dass das kollektive Genie von StackOverflow eine bessere Lösung beleuchten kann.

EDIT:

Am Ende entschied ich mich mit Subklassen die ObservableCollection zu gehen. Der Dienstproxycode wird generiert, sodass es eine relativ einfache Aufgabe war, ihn so zu ändern, dass er meinen abgeleiteten Typ zurückgibt.

Danke für die Hilfe!

+0

Warum nicht schwache Referenzen auf die Entitäten selbst, anstatt die Sammlung zu halten? Dann müssen Sie nicht an der Sammlung herumfummeln, wenn Entitäten entfernt werden. Stellen Sie nur sicher, dass die Referenzen bei der Iteration aktiv sind. –

+0

Wenn Sie schwache Verweise auf Entitäten beibehalten, anstatt sie zu einer Shadow-Auflistung hinzuzufügen, können sie effektiv als Garbage Collected erfasst werden, und ich möchte sie an dem Punkt wiederverwenden können, an dem ich ihren Status in der Datenbank aktualisieren muss. Es macht nur Sinn, sie als Garbage Collected zu betrachten, wenn die ObservableCollection, aus der sie stammen, nicht mehr verfügbar ist. –

+0

Sie könnten ObservableCollection ableiten und IDispose hinzufügen, die Ihren Code benachrichtigt. Es würde Ihren Client-Code jedoch belasten, IDispose aufzurufen. –

Antwort

1

Statt Ihre eigene Walz „schwache Referenz + Umfrage Ist es tot, ist es Alive“ Logik, Sie die HttpRuntime.Cache (erhältlich bei allen Projekttypen, nicht nur Web-Projekte) nutzen könnten.

Fügen Sie jede Schattensammlung dem Cache entweder mit einem großzügigen Zeitlimit oder einem Delegaten hinzu, der überprüfen kann, ob die ursprüngliche Sammlung noch am Leben ist (oder beides).

Es ist nicht schrecklich anders als Ihre eigene Lösung, aber es verwendet bewährte. NET-Komponenten.

Other than that, Sie befinden sich in der ObservableCollection erstreckt, und dass die neue Klasse anstelle (was ich mir vorstellen würde, ist keine kleine Änderung) oder Ändern/Einwickeln UpdateCustomers Methode der Schatten Sammlung bilden DeletedCollections

zu entfernen Tut mir leid, ich kann nicht an etwas anderes denken, aber hoffe, das hilft.
BW

+0

Danke für die Antwort. Ihre Antwort bringt mich dazu, Ansätze, die ich zuvor abgelehnt hatte, wie die Erweiterung von ObservableCollection selbst, zu überdenken. Will die Implikationen der Erweiterung zu untersuchen ... –

+0

Am Ende habe ich beschlossen, die "ObservableCollection" Unterklasse. Die Service-Proxy-Klassen werden trotzdem generiert, sodass die Anzahl der Änderungen auf ein Minimum reduziert wurde. Danke für die Hilfe! –

+0

Ausgezeichnet, froh, Hilfe zu sein, danke :) –

1

Wenn ObservableCollection ersetzt eine Möglichkeit ist, (zum Beispiel, wenn Sie eine gemeinsame Fabrik für alle Sammlungen Instanzen verwenden), dann können Sie ObservableCollection Unterklasse und eine Finalize-Methode hinzufügen, die die gelöschten Objekte bereinigt, die zu dieser Sammlung gehört.

Eine weitere Alternative besteht darin, die Berechnung der gelöschten Elemente zu ändern. Sie können die ursprüngliche Sammlung beibehalten und dem Kunden eine flache Kopie geben. Wenn die Sammlung zurückkommt, können Sie die beiden vergleichen, um festzustellen, welche Elemente nicht mehr vorhanden sind. Wenn die Sammlungen sortiert sind, kann der Vergleich linear zur Größe der Sammlung durchgeführt werden. Wenn sie nicht sortiert sind, können die geänderten Sammlungswerte in eine Hash-Tabelle eingegeben werden, die zum Nachschlagen jedes Werts in der ursprünglichen Sammlung verwendet wird. Wenn die Entitäten eine natürliche ID haben, ist die Verwendung dieses Schlüssels eine sichere Methode, um zu bestimmen, welche Elemente in der zurückgegebenen Sammlung nicht vorhanden sind, dh gelöscht wurden. Dies läuft auch in linearer Zeit.

Ansonsten klingt Ihre ursprüngliche Lösung nicht so schlecht. In Java kann eine WeakReference einen Rückruf registrieren, der aufgerufen wird, wenn die Referenz gelöscht wird. Es gibt keine ähnliche Funktion in .NET, aber die Verwendung von Abfragen ist eine gute Annäherung. Ich glaube nicht, dass diese Herangehensweise so schlecht ist, und wenn sie funktioniert, warum sollte sie dann geändert werden?

Abgesehen davon sind Sie nicht besorgt über GetHashCode() den gleichen Wert für unterschiedliche Sammlungen zurückgeben? Die Verwendung eines schwachen Verweises auf die Sammlung könnte geeigneter sein als der Schlüssel, dann besteht keine Möglichkeit einer Kollision.

+0

Beim Unterklassieren würde ich mich nicht mit Finalisieren beschäftigen müssen. Die Schattensammlung wird nie von woanders referenziert, und ihr Umfang ist an die abgeleitete "Observablecollection" gebunden. Es ist keine Möglichkeit, den Status auf dem Server beizubehalten, und dieser Ansatz würde es mir nicht erlauben, nur die gelöschten Entitäten zurückzusenden, um zum Beispiel Transfer Payload zu reduzieren. Der Teil über 'GetHashCode()' Kollidieren ist etwas, das ich adressieren muss, wenn ich mich entscheide, 'ObservableCollection' nicht zu unterklassen. Noch ein Grund, letzteres zu betrachten :) Danke für die Antwort! –

+0

Sie haben recht damit, dass Sie finalize nicht benötigen, wenn Sie Subclassing durchführen - Sie können die Liste der gelöschten Mitglieder zu einem Mitglied der Sammlung machen. Wie du gemerkt hast, geht das um das hashCode Problem herum, da das auch nicht mehr nötig ist. Aber Ihre aktuelle Lösung, die schwache Referenzen zu einem Hintergrundthread abfragt - ist das so schlimm? – mdma

1

Ich denke, Sie sind auf einem guten Weg, würde ich in dieser Situation Refactoring in Betracht ziehen. Ich habe die Erfahrung gemacht, dass in 99% der Fälle der Garbage Collector die Speicherverwaltung enorm macht - fast keine echte Arbeit wird benötigt.

Aber in den 1% der Fälle braucht es jemanden, der erkennt, dass sie den Ante steigen und "Old School" gehen müssen, indem sie ihr Caching/Speichermanagement in diesen Bereichen festigen. Hut ab vor dir, um zu erkennen, dass du in dieser Situation bist und versuche, die IDispose/WeakReference-Tricks zu vermeiden. Ich denke, du wirst dem nächsten Typen, der in deinem Code arbeitet, wirklich helfen.

Wie für eine Lösung bekommen, denke ich Ihnen einen guten Halt auf dem

-be klare Situation haben, wenn müssen Ihre Objekte erstellt werden -be deutlich, wenn Ihre Objekte -be zerstört werden müssen Löschen, wenn Ihre Objekte auf den Server geschoben werden müssen

viel Glück! sagen Sie uns, wie es geht :)

+0

Danke, am Ende habe ich doch den Code rausgeschmissen. Subclassing ergab mehr Sinn, da es den Bereich der Schattensammlung an die "ObservableCollection" gebunden hat. –

Verwandte Themen