Pregunta

Estamos desarrollando una aplicación .NET con la siguiente arquitectura: capa de presentación (usando el patrón MVC con ASP.NET MVC 2), capa de servicio, capa de acceso a datos (utilizando el patrón de repositorio a través del marco de la entidad).

Hemos decidido poner la gestión de transacciones en la capa de servicio, pero no estamos seguros de cómo implementarla. Queremos controlar la transacción por completo a nivel de capa de servicio. Es decir, cada vez que un controlador llama a un método en la capa de servicio, debe ser una operación atómica con respecto a las actualizaciones de la base de datos.

Si no hubiera relación entre diferentes servicios proporcionados en la capa de servicio, entonces sería simple: cada método debería confirmar los cambios al final de su ejecución (es decir, llamar al método Guardar en el contexto que utiliza). Pero a veces los servicios en la capa de servicio trabajan juntos.

Por ejemplo: proporcionamos un servicio de envío que tiene un método de confirmación que recibe los siguientes parámetros: la identificación de envío, una bandera que indica si corresponde a un nuevo cliente o uno existente, la identificación del cliente (en caso de que la confirmación de envío sea para un existente Cliente) y un nombre del cliente (en caso de que sea para un nuevo cliente). Si el indicador está configurado en "nuevo cliente", entonces la capa de servicio tiene que (a) crear el cliente y (b) confirmar el envío. Para (a) el servicio de envío llama al servicio al cliente (que ya implementa las validaciones y la lógica necesarias para crear un nuevo cliente y almacenarlo en la base de datos).

¿Quién debería cometer los cambios en este escenario?

  • ¿Debería hacerlo el servicio al cliente? No puede confirmar los cambios después de crear el nuevo cliente, porque algo puede salir mal más adelante en el método de confirmación de envío, pero tiene que confirmar sus cambios en el caso de que se llame directamente (en otro caso de uso, proporcionado para crear un cliente).
  • ¿Debería hacerlo el controlador que llama al método de servicio? Pero el controlador no debería saber nada sobre transacciones, hemos decidido poner todo el conocimiento de la transacción en la capa de servicio.
  • ¿Un administrador de transacciones en la capa de servicios? ¿Cómo diseñarlo?, ¿Quién lo llama y cuándo?

¿Hay un patrón de diseño para esto que debamos seguir?

¿Fue útil?

Solución

Tengo un compromiso () en mi servicio, esto solo se compromete si el servicio es creado por el servicio, si se pasa en el constructor, la confirmación no hace nada.

Usé un segundo constructor (interno) para el servicio:

public class MyService
{
private IUnitOfWork _uow;
private bool _uowInternal;

public MyService()
{
    _uow = new UnitOfWork();
    _uowInternal = false;
}

internal MyService(IUnitOfWork uow)
{
    _uow = uow;
    _uowInternal = true;
}
public MyServiceCall()
{
    // Create second service, passing in my UnitOfWork:
    var svc2 = new MySecondService(_uow);

    // Do your stuff with both services.
    ....
    // Commit my UnitOfWork, which will include all changes from svc2:
    Commit();
}

public void Commit()
{
    if(!_uowInternal)
        _uow.Commit();
}
}

Otros consejos

En una arquitectura similar con WCF y L2S en lugar de EF, elegimos usar transacciones en la clase de implementación de interfaz de servicio principal. Nosotros usamos Transaccionescopio lograr esto:

public void AServiceMethod() {
    using(TransactionScope ts = new TransactionScope()) {
         service1.DoSomething();
         service2.DoSomething();
         ts.Complete();
    }
}

La principal desventaja es que la transacción puede ser grande. En ese caso, si, por ejemplo, una de las llamadas de servicio en el bloque de transacciones requiere solo acceso de lectura, lo envolvemos en un anidado TransactionScope(TransactionScopeOption.Suppress) Bloquee para evitar que el bloqueo de las hileras/tablas sea aún más en la vida útil de la transacción.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top