Brandon
Brandon

Reputation: 70022

Why isn't NHibernate tracking changes made to my entities?

I'm using Ninject, Fluent NHibernate and ASP.NET MVC.

Up until now everything has been working fine, I don't get any errors and I'm able to query out of the repositories just fine, but I'm not able to commit any changes.

My controller method looks like this

[HttpPost]
[UnitOfWork]
public ActionResult Method(int id)
{
    // Lookup entity, toggle a bool property on it and that is it
}

My UnitOfWork attribute looks like this

public class UnitOfWorkAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        NHibernateSession.Current.BeginTransaction();
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Exception == null && NHibernateSession.Current.Transaction.IsActive)
        {
            NHibernateSession.Current.Transaction.Commit();
        }
    }
}

Both methods are being called and no errors are raised, the problem is that when NHibernateSession.Current (which just returns NHibernate.ISession) is called, ISession.IsDirty() is false. NHibernate doesn't think anything has changed.

I've used similar setups in other projects before without a problem, the only difference with this one is that I swapped out StructureMap for Ninject, which I'm not that familiar with.

The relevant Bindings are

Bind<IEntityRepository>().To<EntityRepository>().InRequestScope();
Bind<ISessionFactory>().ToMethod(x => NHibernateSession.CreateSessionFactory()).InSingletonScope();
Bind<ISession>().ToMethod(x => x.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();

Any ideas what I've done wrong? I'm guessing it has something to do with me messing up on the session handling, but I'm not sure exactly what.

Edit: This is what the Current call returns. The session should be stored so that a new session doesn't have to be created each time.

public static ISession Current
{
  get
  {
      var session = GetExistingSession();

      if (session != null)
        return session;

      session = _sessionFactory.OpenSession();
      HttpContext.Current.Items[SessionKey] = session;
      return session;
   }
 }

Upvotes: 1

Views: 1005

Answers (2)

dotjoe
dotjoe

Reputation: 26940

You need to use the same ISession for that request, hence the InRequestScope(). You could change NHibernateSession.Current to something like return DependencyResolver.Current.GetService<ISession>(); but it's probably more preferred to ctor inject the ISession into the FilterAttribute and tell ninject about it with this.BindFilter<UnitOfWorkFilter>(FilterScope.Action, 0);

https://github.com/ninject/ninject.web.mvc/wiki/Filter-configurations

Upvotes: 1

Carl Raymond
Carl Raymond

Reputation: 4479

From your comment on your question, I think each time you call NHibernateSession.Current you're getting a new session. That's the problem. Your session needs to have per-web-request lifetime semantics. You'll want to inject the session into your controller or your filter.

Upvotes: 1

Related Questions