visual usan studio que pueden proyectos programas programar para hechos hechas hacer famosos empresas ejemplos crear con aplicaciones c# nhibernate transactions data-access-layer data-access

c# - usan - Nhibernate: ¿Quién es responsable de la gestión de transacciones en una aplicación no web?



proyectos c# ejemplos (2)

Cuando uso repositorios, están contenidos dentro de una unidad de trabajo. La unidad de trabajo realiza un seguimiento de los cambios en los repositorios y maneja la gestión de transacciones.

¿Por qué sería válido usar una unidad de trabajo para manejar la gestión de transacciones en una aplicación web y no en una aplicación de Windows? Si se trata de una aplicación N-Tier, la capa de su empresa se compartiría entre ambos.

Bueno, en una aplicación web, una unidad de trabajo es responsable de la gestión de las transacciones.

Pero, ¿qué pasa con una aplicación de Windows?

Hasta donde sé, el repositorio es el conector entre mi capa de acceso a datos y mi capa de negocios. Oculta todo el material de acceso a datos de mi capa de negocios.

Usando este hecho permítanme pensar en llevar todo el material de transacción al repositorio.

Pero leí que tener los métodos Commit / RollBack en el repositorio está violando la intención del repositorio.

Me pregunto quién es el responsable de la gestión de transacciones en una aplicación no web y cómo oculto la transacción / material de Nhibernate de la capa empresarial.


La respuesta general es "Quien ejemplifique la ISession debe deshacerse de ella. Si la transacción no se ha comprometido, esto es efectivamente una reversión".

Tuve éxito al usar el patrón de comando para definir una operación que deseo realizar en una unidad de trabajo. Digamos que tenemos una entidad Person y una de las cosas que podemos hacer es cambiar el nombre de una persona. Comencemos con la entidad:

public class Person { public virtual int Id { get; private set; } public virtual string Name { get; private set; } public virtual void ChangeName(string newName) { if (string.IsNullOrWhiteSpace(newName)) { throw new DomainException("Name cannot be empty"); } if (newName.Length > 20) { throw new DomainException("Name cannot exceed 20 characters"); } this.Name = newName; } }

Defina un simple comando POCO como este:

public class ChangeNameCommand : IDomainCommand { public ChangeNameCommand(int personId, string newName) { this.PersonId = personId; this.NewName = newName; } public int PersonId { get; set; } public string NewName { get; set; } }

... y un controlador para el comando:

public class ChangeNameCommandHandler : IHandle<ChangeNameCommand> { ISession session; public ChangeNameCommandHandler(ISession session) { // You could demand an IPersonRepository instead of using the session directly. this.session = session; } public void Handle(ChangeNameCommand command) { var person = session.Load<Person>(command.PersonId); person.ChangeName(command.NewName); } }

El objetivo es que el código que existe fuera del alcance de una sesión / trabajo pueda hacer algo como esto:

public class SomeClass { ICommandInvoker invoker; public SomeClass(ICommandInvoker invoker) { this.invoker = invoker; } public void DoSomething() { var command = new ChangeNameCommand(1, "asdf"); invoker.Invoke(command); } }

La invocación del comando implica "hacer este comando en una unidad de trabajo". Esto es lo que queremos que suceda cuando invoquemos el comando:

  1. Comience un alcance anidado de IoC (el alcance de "Unidad de trabajo")
  2. Inicie una ISession y una Transacción (esto probablemente esté implícito como parte del paso 3)
  3. Resolver un IHandle<ChangeNameCommand> desde el alcance de IoC
  4. Pase el comando al controlador (el dominio hace su trabajo)
  5. Confirmar la transacción
  6. Finalizar el alcance de IoC (la Unidad de trabajo)

Así que aquí hay un ejemplo usando Autofac como el contenedor IoC:

public class UnitOfWorkInvoker : ICommandInvoker { Autofac.ILifetimeScope scope; public UnitOfWorkInvoker(Autofac.ILifetimeScope scope) { this.scope = scope; } public void Invoke<TCommand>(TCommand command) where TCommand : IDomainCommand { using (var workScope = scope.BeginLifetimeScope("UnitOfWork")) // step 1 { var handler = workScope.Resolve<IHandle<TCommand>>(); // step 3 (implies step 2) handler.Handle(command); // step 4 var session = workScope.Resolve<NHibernate.ISession>(); session.Transaction.Commit(); // step 5 } // step 6 - When the "workScope" is disposed, Autofac will dispose the ISession. // If an exception was thrown before the commit, the transaction is rolled back. } }

Nota: El UnitOfWorkInvoker que he mostrado aquí está violando el SRP , es un UnitOfWorkFactory , un UnitOfWork y un Invoker todo en uno. En mi implementación real, los eché.