Frage

Ich habe UOW Muster mit so etwas wie einem folgenden Code implementiert gesehen:

    private HashSet<object> _newEntities = new HashSet<object>();
    private HashSet<object> _updatedEntities = new HashSet<object>();
    private HashSet<object> _deletedEntities = new HashSet<object>();

und dann gibt es Methoden für das Hinzufügen von Einheiten zu jedem dieses HashSets.

Auf UnitOfWork Commit erstellt einig Mapper-Instanz für jede Einheit und ruft Insert, Update, Delete Methoden von einem imaginären Mapper.

Das Problem für mich bei diesem Ansatz ist: die Namen von Insert, Update, Delete Methoden sind hartcodiert, so scheint es, eine solche UnitOfWork Lage ist, nur einfache CRUD-Operationen zu tun. Aber was, wenn ich brauche die folgende Nutzung:

UnitOfWork ouw = new UnitOfWork();
uow.Start();

ARepository arep = new ARepository();
BRepository brep = new BRepository(); 

arep.DoSomeNonSimpleUpdateHere();
brep.DoSomeNonSimpleDeleteHere();

uow.Commit();

Nun ist der Drei-HashSet Ansatz versagt, weil ich dann konnte ich A und B Einheiten registriert nur für Insert, Update, Delete-Operationen, aber ich brauche die benutzerdefinierten Operationen jetzt.

So scheint es, dass ich nicht immer , um die Repository-Operationen stapelt und führt sie dann alle mit UnitOfWork.Commit();

Wie dieses Problem zu lösen? Die erste Idee ist - ich könnte speichern Adressen von Methoden

arep.DoSomeNonSimpleUpdateHere();
brep.DoSomeNonSimpleDeleteHere(); 

in UOW Instanz und führen sie auf uow.Commit() aber dann habe ich auch alle Verfahrensparameter zu speichern. Das klingt kompliziert.

Die andere Idee ist Repositorys völlig UOW-bewusst zu machen: In DoSomeNonSimpleUpdateHere kann ich erkennen, dass es eine UOW läuft und damit ich nicht DoSomeNonSimpleUpdateHere durchführen, aber die Betriebsparameter und ‚offen‘ Status in einigen Stapeln der Repository-Instanz speichern (natürlich kann ich nicht alles in UOW sparen, weil UOW nicht auf konkrete Repository Implementierungen abhängen soll). Und dann melde ich mich an die beteiligten Repository in der UOW-Instanz. Wenn UOW Commit aufruft, öffnet sie eine Transaktion, und nennt einige Sache wie Flush () für jede ausstehende Repository. Jetzt jede Methode von Repository muss ein paar Sachen für UOW Erkennung und Betrieb für die späteren Commit() verschieben.

So die kurze Frage ist - was der einfachste Weg ist, um alle anstehenden Änderungen in mehreren Repositorys in UOW registrieren und dann Commit() sie alle in einer einzigen Transaktion

War es hilfreich?

Lösung

Es scheint, dass auch komplizierte Updates in eine Reihe von Änderungen aufgeschlüsselt nach einem oder mehreren DomainObjects werden kann. Aufruf DoSomeNonSimpleUpdateHere () modifizieren kann mehrere verschiedene DomainObjects, die entsprechenden Anrufe an UnitOfWork.registerDirty (Domainobject) auslösen würde für jedes Objekt. In dem folgenden Beispielcode habe ich den Anruf zu DoSomeNonSimpleUpdateHere mit Code ersetzt, die inaktiven Benutzer aus dem System entfernt.

UnitOfWork uow = GetSession().GetUnitOfWork();
uow.Start();

UserRepository repository = new UserRespository();
UserList users = repository.GetAllUsers();

foreach (User user in users)
{
  if (!user.IsActive())
    users.Remove( user );
}

uow.Commit();

Wenn Sie besorgt sind über alle Benutzer zu iterieren haben, hier ist ein alternativer Ansatz, der ein Criteria-Objekt verwendet die Anzahl der Benutzer aus der Datenbank gezogen zu begrenzen.

UnitOfWork uow = GetSession().GetUnitOfWork();
uow.Start();

Repository repository = new UserRespository();
Criteria inactiveUsersCriteria = new Criteria();
inactiveUsersCriteria.equal( User.ACTIVATED, 0 );
UserList inactiveUsers = repository.GetMatching( inactiveUsersCriteria );
inactiveUsers.RemoveAll();

uow.Commit();

Die UserList.Remove und UserList.RemoveAll Methoden werden die UnitOfWork jeder entfernt Benutzer benachrichtigen. Wenn UnitOfWork.Commit () aufgerufen wird, wird es jeden Benutzer in seinen _deletedEntities gefunden löschen. Dieser Ansatz ermöglicht es Ihnen, beliebig komplexen Code zu erstellen, ohne dass SQL-Abfragen für jeden speziellen Fall zu schreiben. Mit der dosierten Updates werden hier nützlich sein, da die UnitOfWork werden mehrere Lösch Aussagen statt nur eine Anweisung für alle aktiven Benutzer ausführen müssen.

Andere Tipps

Die Tatsache, dass Sie dieses Problem haben zeigt, dass Sie nicht das Repository-Muster als solche verwenden, aber so etwas wie mehrere Tabellendaten-Gateways. Im Allgemeinen ist ein Repository für das Laden und Speichern ein Aggregat Wurzel. Als solcher, wenn Sie ein Objekt speichern, speichert Ihre Persistenz-Schicht alle Änderungen in diesem Aggregat Wurzel Objektgraphen des Entity-Instanz.

Wenn in Ihrem Code, haben Sie etwa einen „Repository“ pro einer Tabelle (oder Entity), sind Sie wahrscheinlich tatsächlich ein Tabellendatum-Gateway oder ein Datenübertragungsobjekt verwenden. In diesem Fall müssen Sie wahrscheinlich ein Mittel zur Weitergabe in Bezug auf die aktive Transaktion haben (oder die Arbeitseinheit) in jeder Methode Save ().

In Evans DDD Buch, er rät, Transaktionssteuerung an den Client eines Endlagers, und ich würde zustimmen, dass es keine gute Praxis ist, obwohl es schwieriger sein kann, zu vermeiden, wenn Sie tatsächlich eine Tabelle Datengateway Muster.

Schließlich fand ich diese:

http://www.goeleven.com/Blog/82

Der Autor löst das Problem mit drei Listen für Updates / Einfügen / Löschen, aber er Entitäten nicht dort speichern. Stattdessen Repository Delegierten und deren Parameter gespeichert sind. Also auf Commit der Autor Anrufe jeder registrierte Delegierte. Mit diesem Ansatz konnte ich auch einige komplexe Repository Methoden registrieren und so vermeiden, dass ein separater TableDataGateway verwenden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top