Transacciones en varios methods DAL del único método en el BLL

¿Cómo haría para llamar a varios methods en la capa de acceso a datos desde un método en la capa de lógica de negocios para que todos los commands SQL vivieran en una transacción SQL?

Cada uno de los methods DAL se puede llamar individualmente desde otros lugares en el BLL, por lo que no hay garantía de que los methods de capa de datos siempre sean parte de una transacción. Necesitamos esta funcionalidad, de modo que si la database se desconecta en medio de un process de ejecución prolongada, no hay compromiso. La capa empresarial está orquestando diferentes llamadas a methods de capa de datos basadas en los resultados de cada una de las llamadas anteriores. Solo queremos comprometernos (desde la capa de negocios) al final de todo el process.

Bueno, en primer lugar, deberá adherirse a una Unidad de trabajo atómica que especifique como un único método en su BLL. Esto (por ejemplo) crearía el cliente, el pedido y los artículos del pedido. Luego, envuelve todo esto dentro de una statement de uso de TransactionScope. TransactionScope es el arma secreta aquí. a continuación hay un código que afortunadamente estoy trabajando en este momento :):

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 requinetworking */ 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; } 

con suerte, obtendrá la esencia. Básicamente, es un trabajo exitoso o fallido, independientemente de cualquier database diferente (es decir, en el ejemplo anterior, el artista y el artistartistgenre podrían estar alojados en dos tiendas independientes, pero a TransactionScope no le importa eso, funciona a nivel COM + y administra la atomicidad del scope que puede 'ver')

espero que esto ayude

EDITAR: posiblemente encontrará que la invocación inicial de TransactionScope (al inicio de la aplicación) puede ser ligeramente perceptible (es decir, en el ejemplo anterior, si se le llamó por primera vez, puede tardar 2-3 segundos en completarse), sin embargo, las llamadas subsiguientes son casi instantáneas (es decir, típicamente 250-750 ms). el intercambio entre una simple transacción de punto de contacto versus las alternativas (difíciles de manejar) mitiga (para mí y para mis clientes) esa latencia inicial de "carga".

solo quería demostrar que la facilidad no viene sin compromiso (aunque en las etapas iniciales)

Lo que describes es la misma 'definición' de una transacción larga.

Cada método DAL podría simplemente proporcionar operaciones (sin compromisos específicos). Su BLL (que está en efecto donde coordina cualquier llamada al DAL de todos modos) es donde puede elegir entre confirmar o ejecutar un 'punto de rescate'. Un punto de rescate es un elemento opcional que puede emplear para permitir 'retrocesos' dentro de una transacción de larga ejecución.

Entonces, por ejemplo, si mi DAL tiene los methods DAL1, DAL2, DAL3 son mutantes, simplemente 'ejecutarían' las operaciones de cambio de datos (es decir, algún tipo de Crear, Actualizar, Eliminar). Desde mi BLL, supongamos que tengo methods BL1 y BL2 (BL1 es de larga duración). BL1 invoca todos los methods DAL mencionados anteriormente (es decir, DAL1 … DAL3), mientras que BL2, solo invoca DAL3.

Por lo tanto, en la ejecución de cada método de lógica de negocios, es posible que tenga lo siguiente:

BL1 (transacción larga) -> {savepoint} DAL1 -> {savepoint} DAL2 -> DAL3 {commit / end}

BL2 -> DAL3 {commit / end}

La idea detrás del 'punto de rescate' es que puede permitir que BL1 se deshaga en cualquier punto si hay problemas en las operaciones de datos. La transacción larga SOLO se compromete si las tres operaciones se completan satisfactoriamente. BL2 todavía puede llamar a cualquier método en el DAL, y es responsable de controlar los commits. NOTA: también puede usar 'puntos guardados' en transactions cortas / regulares.

Buena pregunta. Esto llega al corazón del desajuste de impedancia.

Este es uno de los arguments más sólidos para usar procedimientos almacenados. Motivo: están diseñados para encapsular múltiples declaraciones SQL en una transacción.

Lo mismo se puede hacer procedimentalmente en el DAL, pero da como resultado un código con less claridad, mientras que generalmente resulta en mover el equilibrio de cohesión / cohesión en la dirección incorrecta.

Por esta razón, implemento el DAL en un nivel más alto de abstracción que simplemente encapsulando tablas.

en caso de que mi comentario en el artículo original no se "quedara", esto es lo que agregué como información adicional:

<—– coincidentemente, acaba de notar otra reference similar publicada unas horas después de su request. utiliza una estrategia similar y puede valer la pena que también la veas: http://stackoverflow.com/questions/494550/how-does-transactionscope-roll-back-transactions —–>