Transazioni su più metodi DAL dall’unico metodo nella BLL

Come andresti a chiamare diversi metodi nel livello di accesso ai dati da un metodo nel livello della logica aziendale in modo che tutti i comandi SQL vivessero in una transazione SQL?

Ognuno dei metodi DAL può essere chiamato singolarmente da altri posti nella BLL, quindi non vi è alcuna garanzia che i metodi del livello dati siano sempre parte di una transazione. Abbiamo bisogno di questa funzionalità, quindi se il database si disconnette nel mezzo di un lungo processo in esecuzione, non c’è commit. Il livello aziendale sta orchestrando diverse chiamate al metodo del livello dati in base ai risultati di ciascuna delle chiamate precedenti. Vogliamo solo impegnarci (dal livello aziendale) alla fine dell’intero processo.

beh, in primo luogo, devi aderire a un’unità di lavoro atomica che specifichi come singolo metodo nel tuo BLL. Questo (ad esempio) creerebbe il cliente, l’ordine e gli articoli dell’ordine. allora dovresti avvolgere tutto questo in un TransactionScope usando l’istruzione. TransactionScope è l’arma segreta qui. sotto c’è un codice che per fortuna sto lavorando proprio ora :):

public static int InsertArtist(Artist artist) { if (artist == null) throw new ArgumentNullException("artist"); int artistid = 0; using (TransactionScope scope = new TransactionScope()) { // insert the master Artist /* we plug the artistid variable into any child instance where ArtistID is required */ artistid = SiteProvider.Artist.InsertArtist(new ArtistDetails( 0, artist.BandName, artist.DateAdded)); // insert the child ArtistArtistGenre artist.ArtistArtistGenres.ForEach(item => { var artistartistgenre = new ArtistArtistGenreDetails( 0, artistid, item.ArtistGenreID); SiteProvider.Artist.InsertArtistArtistGenre(artistartistgenre); }); // insert the child ArtistLink artist.ArtistLinks.ForEach(item => { var artistlink = new ArtistLinkDetails( 0, artistid, item.LinkURL); SiteProvider.Artist.InsertArtistLink(artistlink); }); // insert the child ArtistProfile artist.ArtistProfiles.ForEach(item => { var artistprofile = new ArtistProfileDetails( 0, artistid, item.Profile); SiteProvider.Artist.InsertArtistProfile(artistprofile); }); // insert the child FestivalArtist artist.FestivalArtists.ForEach(item => { var festivalartist = new FestivalArtistDetails( 0, item.FestivalID, artistid, item.AvailableFromDate, item.AvailableToDate, item.DateAdded); SiteProvider.Festival.InsertFestivalArtist(festivalartist); }); BizObject.PurgeCacheItems(String.Format(ARTISTARTISTGENRE_ALL_KEY, String.Empty, String.Empty)); BizObject.PurgeCacheItems(String.Format(ARTISTLINK_ALL_KEY, String.Empty, String.Empty)); BizObject.PurgeCacheItems(String.Format(ARTISTPROFILE_ALL_KEY, String.Empty, String.Empty)); BizObject.PurgeCacheItems(String.Format(FESTIVALARTIST_ALL_KEY, String.Empty, String.Empty)); BizObject.PurgeCacheItems(String.Format(ARTIST_ALL_KEY, String.Empty, String.Empty)); // commit the entire transaction - all or nothing scope.Complete(); } return artistid; } 

si spera, otterrete l’essenza. fondamentalmente, è un lavoro di successo o di fallimento, indipendentemente da qualsiasi database disparato (ad esempio nell’esempio sopra, artista e artistaartista possono essere ospitati in due negozi DB separati ma TransactionScope si preoccuperà di meno, funziona a livello di COM + e gestisce l’atomicità dello scopo che può ‘vedere’)

spero che questo ti aiuti

EDIT: probabilmente troverai che l’invocazione iniziale di TransactionScope (all’avvio dell’app) potrebbe essere leggermente evidente (ad esempio nell’esempio sopra, se è stata chiamata per la prima volta, possono essere necessari 2-3 secondi per completare), tuttavia, le chiamate successive sono quasi istantanee (ovvero in genere 250-750 ms). il compromesso tra una semplice transazione punto di contatto e le alternative (ingombranti) mitiga (per me e i miei clienti) quella iniziale “caricamento” della latenza.

volevo solo dimostrare che la facilità non viene senza compromessi (anche se nelle fasi iniziali)

Quello che descrivi è la ‘definizione’ di una lunga transazione.

Ogni metodo DAL potrebbe semplicemente fornire operazioni (senza alcun commit specifico). Il tuo BLL (che è in effetti in cui si stanno coordinando le chiamate al DAL) è dove è ansible scegliere di eseguire il commit o eseguire un “punto di salvataggio”. Un punto di salvataggio è un elemento facoltativo che è ansible utilizzare per consentire i “rollback” all’interno di una transazione di lunga durata.

Quindi, ad esempio, se il mio DAL ha i metodi DAL1, DAL2, DAL3 sono tutti mutativi, eseguono semplicemente operazioni di modifica dei dati (ad esempio un tipo di Crea, Aggiorna, Elimina). Dal mio BLL, supponiamo di avere i metodi BL1 e BL2 (BL1 è di lunga durata). BL1 richiama tutti i metodi DAL summenzionati (cioè DAL1 … DAL3), mentre BL2, richiama solo DAL3.

Pertanto, all’esecuzione di ciascun metodo di business logic si potrebbe avere il seguente:

BL1 (long-transaction) -> {savepoint} DAL1 -> {savepoint} DAL2 -> DAL3 {commit / end}

BL2 -> DAL3 {commit / end}

L’idea alla base del “punto di salvataggio” è che può consentire al BL1 di eseguire il rollback in qualsiasi punto se ci sono problemi nelle operazioni dei dati. La transazione lunga viene triggersta SOLO se tutte e tre le operazioni vengono completate correttamente. BL2 può ancora chiamare qualsiasi metodo nel DAL ed è responsabile del controllo dei commit. NOTA: è ansible utilizzare “punti di salvataggio” anche in transazioni corte / regolari.

Buona domanda. Questo arriva al cuore della mancata corrispondenza dell’impedenza.

Questo è uno degli argomenti più forti per l’utilizzo delle stored procedure. Motivo: sono progettati per incapsulare più istruzioni SQL in una transazione.

Lo stesso può essere fatto proceduralmente nel DAL, ma risulta in codice con meno chiarezza, mentre di solito risulta spostando il bilanciamento di accoppiamento / coesione nella direzione sbagliata.

Per questo motivo, implemento il DAL a un livello più alto di astrazione rispetto alle semplici tabelle incapsulanti.

nel caso in cui il mio commento nell’articolo originale non fosse “incollato”, ecco cosa ho aggiunto come informazioni aggiuntive:

< ----- per coincidenza, ho appena notato un altro riferimento simile a questo pubblicato poche ore dopo la tua richiesta. usa una strategia simile e potrebbe valere anche la pena di guardarla: http://stackoverflow.com/questions/494550/how-does-transactionscope-roll-back-transactions ----->