Quello che stai cercando non è impossibile, ma la validità di farlo è un po 'discutibile. Per prima cosa ti darò una risposta diretta alla tua domanda, ma ti suggerisco di rivalutare se questa è una soluzione desiderabile.
What would be considered the better way forward?
Il problema non è un problema tecnico, ma quello di capire cosa vuoi fare.
- Consideri l'aggiornamento di pagamento e di controllo come una singola transazione.
- Consideri l'aggiornamento del pagamento e l'aggiornamento di verifica come transazioni separate.
(1) è quello che hai ora, la tua domanda ti sta chiedendo come ottenere (2).
So I'm a little bit stuck as to how I would implement such a mechanism without having multiple patterns in our domain layer.
Non vedo la difficoltà tecnica qui. Un'unità di modello di lavoro non vieta di avere transazioni separate. Ogni transazione ha lo stesso flusso di lavoro: aggiungi tutte le modifiche necessarie, quindi effettua il commit della transazione.
Ci sono due approcci qui. L'approccio migliore dipende dal tuo scenario specifico.
1
È possibile riutilizzare la stessa unità di lavoro (oggetto memoria) per eseguire sia l'aggiornamento del pagamento che l'aggiornamento di verifica. Tutto quello che devi fare è fare separare le due operazioni nel codice. Effettua tutta la logica di aggiornamento dei pagamenti, esegui il commit, esegui tutta la logica di aggiornamento del controllo, effettua il commit.
2
È possibile utilizzare diverse unità di lavoro (oggetti di memoria), una per i pagamenti e una per il controllo. Ciò comporta un sovraccarico maggiore per manipolare i due oggetti, ma rende più semplice impedire che la logica di aggiornamento dei pagamenti / audit aggiunga le sue modifiche alla transazione errata per errore.
Ci sono anche casi in cui gli aggiornamenti non possono essere separati senza creare altri problemi. Ad esempio, supponiamo che questa sia la tua logica di aggiornamento:
FooHandler.Update(myUOW);
BarHandler.Update(myUOW);
myUOW.Commit();
Ciascuno di questi gestori genera aggiornamenti sia di pagamento che di controllo. Se dovessi riutilizzare lo stesso oggetto UOW, saresti costretto a dividere la logica:
FooHandler.UpdatePayments(myUOW);
BarHandler.UpdatePayments(myUOW);
myUOW.Commit(); //Commit payment update
FooHandler.UpdateAudit(myUOW);
BarHandler.UpdateAudit(myUOW);
myUOW.Commit(); //Commit audit update
Non solo è più brutto, ma può anche ostacolare le prestazioni se i metodi sono pesanti in termini di risorse, probabilmente causando la necessità di dover ripetere parte del lavoro.
Invece, è meglio avere due oggetti separati, poiché puoi evitare di dover separare la logica:
FooHandler.Update(myPaymentUOW, myAuditUOW);
BarHandler.Update(myPaymentUOW, myAuditUOW);
myPaymentUOW.Commit();
myAuditUOW.Commit();
Ho omesso il try / catch che ci si aspetta di vedere attorno ai commit.
Come ultima menzione, e possibilmente un avvertimento, voglio concentrarmi sul commento di Telastyn:
Frankly, if you're auditing anything involving money, it should rollback the actual transaction too if the audit fails.
Ogni ragioniere / impiegato finanziario shoudl rabbrividisce al pensiero di voi che apportate modifiche ai dati senza registrare le modifiche in modo che possa essere rintracciato se necessario. Questo è esattamente ciò che si intende fare un audit.
Dubito strongmente che qualcuno, cliente / imprenditore, approvi il software finanziario che apporta modifiche ai saldi senza generare la traccia cartacea necessaria.
In secondo luogo, mi aspetto che i dati di audit vengano generati automaticamente dal sistema ogni volta che registra una modifica, contrariamente alla logica aziendale che ottiene l'autonomia per decidere se aggiungere aggiornamenti di verifica.
In terzo luogo, anche se questo potrebbe essere più un argomento semantico che pratico, ma se l'aggiornamento di controllo fosse veramente opzionale, dovresti riferirti ad esso come logging , non come auditing.