I'm using ASP.NET MVC 3 and am using the repository and unit of work patterns with NHibernate and Ninject. I looked at a couple examples (1, 2) to help implement UoW, and I'm just not sure where I should be using the unit of work. Should it be injected within my controllers, and manually call Commit and Rollback in my actions?
Here's some code examples:
Unit of work (interface extends IDisposable and has Session, Commit and Rollback)
public class UnitOfWork : IUnitOfWork
{
private readonly ISessionFactory _sessionFactory;
private readonly ITransaction _transaction;
public UnitOfWork(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
Session = _sessionFactory.OpenSession();
Session.FlushMode = FlushMode.Auto;
_transaction = Session.BeginTransaction(IsolationLevel.ReadCommitted);
}
public ISession Session { get; private set; }
public void Commit()
{
if (!_transaction.IsActive)
{
throw new InvalidOperationException("No active transation");
}
_transaction.Commit();
}
public void Rollback()
{
if (_transaction.IsActive)
{
_transaction.Rollback();
}
}
public void Dispose()
{
if (Session.IsOpen)
Session.Close();
}
}
Part of my Ninject module:
Bind<IXXXRepository>().To<XXXRepository>().InRequestScope();
Bind<IYYYRepository>().To<YYYRepository>().InRequestScope();
...
Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
Bind<ISessionFactory>().ToMethod(x => NHibernateHelper.CreateConfiguration(Path.Combine(
HostingEnvironment.ApplicationPhysicalPath,
"bin",
"hibernate.cfg.xml")).BuildSessionFactory()).InSingletonScope();
Bind<ISession>().ToMethod(x => x.Kernel.Get<IUnitOfWork>().Session).InRequestScope();
All my repositories inherit from a class that gets an ISession injected, and as I said earlier in the post I'm injecting the IUnitOfWork into my controllers and calling Commit and Rollback as necessary. Am I doing this right? Should I only be calling Commit when I'm doing updates or deletes, and don't worry about calling it at all for selects? Will that leave a hanging transaction at the end of every request?
I like to use an ActionFilter to automatically begin/commit the unit of work around every request. This works great for 95% of my actions. For the few more complex ones I'll inject the UoW and manage it explicitly from either the controller or the service.
I normally just inject the ISession to the UnitOfWork, as well as to the repositories. There's really no reason a repository should be aware of a unit of work, it shouldn't be touching the transaction at all.
Related
I just start learning castle windsor. Have a quesiton about if I should add another unit of work on top of Nhibernate ISession.
I found this on windsor tutorial.
http://docs.castleproject.org/Windsor.Windsor-Tutorial-Part-Six-Persistence-Layer.ashx
"There's one important, although invisible effect of what we just did. By registering the components we didn't just tell Windsor how to create them. Windsor will also take care of properly destroying the instances for us, thus taking care of managing their full lifetime. In layman terms, Windsor will dispose both objects when they are no longer being used. This means it will flush the changes we made to ISession to the database for us, and it will clean up the ISessionFactory. And we get all of this for free. "
it sounds that we dont need to commit our changes to the Database, Windsor will take care of that. I am assuming Windsor will do that after the page is closed or fully loaded.
now I see other people add another Unit of work on top of Nhibrenate like this one.
Just curious which one is considered the best practice?
UnitOfWork unitOfWork = new UnitOfWork(session);
Repository<Truck> repository = new Repository<Truck>(unitOfWork.Session);
Truck truck = CreateTruck(string.Format("Truck {0}", i + 1), 1000);
repository.Add(truck);
unitOfWork.Commit();
namespace RepositoryPattern.Data.Orm.nHibernate
{
public class UnitOfWork : IUnitOfWork
{
public ISession Session { get; private set; }
private readonly ITransaction _transaction;
public UnitOfWork(ISession session)
{
Session = session
Session.FlushMode = FlushMode.Auto;
_transaction = Session.BeginTransaction(IsolationLevel.ReadCommitted);
}
public void Commit()
{
if (!_transaction.IsActive)
{
throw new InvalidOperationException("Oops! We don't have an active transaction");
}
_transaction.Commit();
}
public void Rollback()
{
if (_transaction.IsActive)
{
_transaction.Rollback();
}
}
public void Dispose()
{
if (Session.IsOpen)
{
Session.Close();
}
}
}
}
Not sure, but I would not go this route. Looks overly complex. Is there a Reason you do not want to use using(session.open..) { ... } ?
Hi I start learn NHibernate and now I am trying create own repository class for NHibernate.
I found many articles about this thema. I chose this tutorial: http://dotnetslackers.com/Community/blogs/antrad/archive/2008/10/25/about-repository-pattern-and-nhibernate.aspx
I am little confuse how handle with transaction in repository.
I have repository interface:
public interface IRepository<T> where T : class
{
void Commit();
void RollBack();
void BeginTransaction();
//...
}
My question is why is good begin transaction in constructor class of repository.
This part of code is from blog on top.
public class NHibRepository<T> :IRepository<T>
where T : class
{
#region Private fields
private ISession _session;
#endregion
#region Constructor
public NHibRepository(ISession session)
{
_session = NHibernateSessionManager.Instance.GetSession();
//why begin transaction where???
_session.BeginTransaction();
}
#endregion
#region Trans
public void Commit()
{
if (session.Transaction.IsActive)
{
session.Transaction.Commit();
}
}
public void Rollback()
{
if (session.Transaction.IsActive)
{
session.Transaction.Rollback();
session.Clear();
}
}
public void BeginTransaction()
{
Rollback();
session.BeginTransaction();
}
#endregion
}
I update this repository and now I use this solution:
public class NHibRepository<T> :IRepository<T>
where T : class
{
#region Private fields
private ISession _session;
#endregion
#region Constructor
public NHibRepository(ISession session)
{
_session = session;
}
#endregion
#region Trans
public void Commit()
{
using (var trans=_session.BeginTransaction())
{
trans.Commit();
}
}
public void RollBack()
{
using (var trans = _session.BeginTransaction())
{
trans.Rollback();
}
}
public void BeginTransaction()
{
throw new NotImplementedException();
}
#endregion
}
My first question is which solution is better and why? or what is correct why?
And my second question is how open session for repository class, now I use this helper class:
public class NHibeHelper
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
InitializeSessionFactory();
return _sessionFactory;
}
}
private static void InitializeSessionFactory()
{
_sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(
#"Server=Zues\SQLEXPRESS;Database=TEST;Trusted_Connection=True;")
)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<UserMap>().Conventions.Add(DefaultCascade.All()))
.ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(true, true))
.BuildSessionFactory();
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
On use like this:
_userRepo = new NHibRepository<User>(NHibeHelper.OpenSession());
Looking at the two options you've presented for transaction management, they both actually have issues.
In example 1, the transaction isn't necessarily disposed, and also you're linking the lifetime of the transaction to the lifetime of the repository. This isn't necessarily a bad thing but unless you're using an IoC container or some other method to ensure that the repository is recreated for each database operation, you will only be able to commit once, and subsequent commits will probably fail.
Example 2 will unfortunately not work at all - in Commit/RollBack you are starting a new transaction every time. Especially in the case of RollBack, if this was called from external code while in the context of a transaction, all you will do is start a new nested transaction and then immediately roll it back. Not very useful unfortunately.
My personal solution to your first question is to pull transaction management away from the repository by using the ambient transactions in System.Transactions. This way you still have separation as ambient transactions are provider-agnostic, but also you have more control about what of many repository operations you might be performing will be involved in the transaction, rather than always using the single-transaction-per-operation model. See http://msdn.microsoft.com/en-us/magazine/cc163527.aspx for more info.
As for your second question, I would highly recommend looking into an IoC container like Castle Windsor or Unity. The helper class you have there is far better than rebuilding the session factory and such every time, but by using an IoC container you can very easily ensure the lifetime of your session object is exactly what you want it to be. For instance, in a number of WCF Per-Call services I'm working on, I use Castle Windsor to ensure that the session is created (and injected into the repository) when the WCF operation begins, and is disposed (along with the repository) when it ends.
There is a collection of data in the database on which a integration test is run. For preventing NHibernate persisting objects modification in the database an EventListener that inherits from DefaultSaveOrUpdateEventListener was implemented.
Then there is a method:
public override void OnSaveOrUpdate(SaveOrUpdateEvent #event)
{
#event.Session.CancelQuery();
Trace.TraceWarning("NhibernateSaveUpdateCanceler: Persistence will be ignored.");
}
Unfortunately this does not work as expected. So intended behavior is to catch the moment when changes are written in the database and cancel it somehow though leaving objects as there are so modification on them can be validated.
Thanks.
EDIT
Cannot do this because there are multiple transaction in the tested method so there is contradiction in requirements by persisting changes so that there are available for all transaction from one side and that changes are not persistent in the database from the other.
The SaveOrUpdate event listener is called when session.Save or session.Update is called. When changes are flushed, the FlushEntity event is called for each entity. Implement IFlushEntityEventListener.
re-write your integration test with an Integration test fixture base. in the base class create:
a fixture setup that initializes nhibernate and creates a session factory
a fixture teardown that closes the session factory
a test setup that creates a session and transaction
a test teardown that rolls back the transaction and closes the session.
like this
[TestFixture]
public abstract class TestFixtureBase
{
protected ISessionFactory SessionFactory { get; private set; }
protected ISession Session { get; private set; }
protected ITransaction Tx { get; private set; }
[TestFixtureSetUp]
public virtual void SetUp()
{
var nh = new NHInit();
nh.Initialize();
SessionFactory = nh.SessionFactory;
}
[TestFixtureTearDown]
public virtual void TearDown()
{
SessionFactory.Close();
}
[SetUp]
public void Test_Set_Up()
{
Session = SessionFactory.OpenSession();
Tx = Session.BeginTransaction();
}
[TearDown]
public void Test_tear_down()
{
Tx.Rollback();
Tx.Dispose();
Session.Close();
}
}
then write your test.
I have wrapped the NHibernate session in my own IDataContext. My NHibernate implementation of this is as follows:
public class NHibernateDataContext : IDataContext {
private readonly ISession _session;
public NHibernateDataContext(ISession session) {
_session = session;
Begin();
}
public IRepository<T> Repository<T>() where T : class {
return new NHibernateRepository<T>(_session);
}
public void Begin() {
if (!_session.Transaction.IsActive)
_session.BeginTransaction();
}
public void Commit() {
if (_session.Transaction.IsActive)
_session.Transaction.Commit();
}
public void Dispose() {
_session.Close();
}
}
public class NHibernateRepository<T> : IRepository<T> where T : class {
private readonly ISession _session;
public NHibernateRepository(ISession session) {
_session = session;
}
public IQueryable<T> GetAll() {
return _session.Query<T>();
}
public T GetByID(int id) {
return _session.Get<T>(id);
}
public void Insert(T entity) {
_session.SaveOrUpdate(entity);
}
public void Delete(T entity) {
_session.Delete(entity);
}
}
Using Microsoft Unity i then register this by saying:
// Configure the container
container.RegisterType<ISessionFactory>(new ContainerControlledLifetimeManager(), new InjectionFactory(c => {
return CreateSessionFactory();
}));
container.RegisterType<ISession>(new InjectionFactory(c => {
var sessionFactory = container.Resolve<ISessionFactory>();
return sessionFactory.OpenSession();
}));
container.RegisterType<IDataContext, NHibernateDataContext>(new PerRequestLifetimeManager<IDataContext>());
So far so good, but my application needs to produce some large reports. I have found that they get exponentially slower due to the 1st level cache bloating. I understand the IStatelessSession interface allows me to do this.
How can i refactor my application so that i can easily use the IStatelessSession instead ISession when querying some data? Please note that for every request i would still like to have an ISession open, but only an IStatelessSession when i need it.
I'd appreciate the help. Thanks
IStatelessSession behavior is significantly different from ISession:
A stateless session does not implement a first-level cache nor
interact with any second-level cache, nor does it implement
transactional write-behind or automatic dirty checking, nor do
operations cascade to associated instances. Collections are ignored by
a stateless session. Operations performed via a stateless session
bypass NHibernate's event model and interceptors. Stateless sessions
are vulnerable to data aliasing effects, due to the lack of a
first-level cache.
You can fight 1st level cache bloating by calling ISession.Clear periodically, say every 500 loaded objects. Otherwise you can just create a new 'context' (but be prepared for unexpected behavior).
public class NHibernateStatelessDataContext : IDataContext {
private readonly IStatelessSession _session;
...
}
I have a repository like so:
public interface IRepository
{
void Save<T>(T entity);
void Create<T>(T entity);
void Update<T>(T entity);
void Delete<T>(T entity);
IQueryable<T> GetAll<T>();
}
My question is, where should my transaction boundaries be? Should I open a new transaction on every method and commit it before returning? Or should it be around the entire repository so that the transaction is only committed when the repository is disposed/garbage collected?
Transactions should not be applied to repositories, because if more than one needs to participate in a transaction there's no way to say it.
Have a separate service tier that uses repositories and model objects to satisfy use cases. The service methods know where the transaction boundaries need to be. That's where they should be applied.
Unit of Work is definitely the way to go. If you're using SQL Server with a local database, TransactionScope will do most of the heavy lifting for you; as long as you share sessions between repositories (which you're doing through constructor injection, right...?), then you can nest these to your heart's content. By default, it enlists in the "ambient" transaction if there is one, and starts a new one if there isn't, which is exactly the behaviour you want for a unit of work.
So your repositories might look like this:
public class UserRepository : IUserRepository
{
public UserRepository(ISession session)
{
this.Session = session;
}
public void Save(User user)
{
using (TransactionScope tsc = new TransactionScope())
{
Session.Save(user);
tsc.Complete();
}
}
protected ISession Session { get; set; }
}
public class OrderRepository : IOrderRepository
{
public OrderRepository(ISession session)
{
this.Session = session;
}
public void Save(Order order)
{
using (TransactionScope tsc = new TransactionScope())
{
Session.Save(order);
tsc.Complete();
}
}
protected ISession Session { get; set; }
}
Then you can perform the complete unit of work like so:
User currentUser = GetCurrentUser();
using (TransactionScope tsc = new TransactionScope())
{
ISession session = SessionFactory.OpenSession();
Order order = new Order(...);
order.User = currentUser;
IOrderRepository orderRepository = GetOrderRepository(session);
orderRepository.Save(order);
currentUser.LastOrderDate = DateTime.Now;
IUserRepository userRepository = GetUserRepository(session);
userRepository.Save(currentUser);
tsc.Complete();
}
If you don't like TransactionScope or your environment prevents you from using it effectively then you can always implement your own UOW or use an existing implementation. Or if you're just an architectural neat-freak then you can do both - use a generic unit-of-work interface with one of the main DI libraries, and implement your concrete UOW using the TransactionScope.
One of the options is the unit of work pattern. This is already explained in several previous questions.