Nhibernate: Who is responsible for managing transactions in a non-web application

The web application is responsible for transaction management.

But what about a windows application?

As far as I know, a repository is a connector between my data access level and my business layer. It hides all data access materials from my business layer.

Using this fact, let me think about taking all the transaction materials into the repository.

But I read that using Commit / RollBack methods in the repository violates the intention of the repository.

I ask myself who is responsible for managing transactions in a non-web application and how to hide transaction / Nhibernate data from the business layer?

+8
c # data-access nhibernate data-access-layer transactions
source share
2 answers

The general answer is: "Whoever creates the ISession instance must get rid of it. If the transaction has not been completed, this is really a rollback."

I had success using the command template to determine the operation I want to perform on a unit of work. Say we have a Person object, and one of the things we can do is change the person’s name. Start with the object:

 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; } } 

Define a simple POCO command as follows:

 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; } } 

... and a handler for the command:

 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); } } 

The goal is that code that exists outside the scope of the session / work can do something like this:

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

Calling a command means "execute this command on a unit of work." This is what we want to do when we invoke the command:

  • Start nested IoC scope ("Unit of work" scope)
  • Run ISession and Transaction (this is probably implied as part of step 3)
  • Allow IHandle<ChangeNameCommand> from IoC scope
  • Pass the command to the handler (the domain does its job)
  • Commit transaction
  • Complete IoC scope (unit of work)

So here is an example of using Autofac as an IoC container:

 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. } } 

Note. The UnitOfWorkInvoker shown here violates SRP - these are UnitOfWorkFactory , a UnitOfWork and a Invoker all in one. In my real implementation, I violated them.

+4
source share

When I use repositories, they are contained within the unit of work. The unit of work tracks changes on the repository and processes transaction management.

Why would it be wise to use a unit of work for transaction management in a web application rather than in a Windows application? If this is an N-Tier app, your business layer will actually be shared between them.

+1
source share

All Articles