Question

I have a MVC5 application and set my hibernate stuff up like that:

  public class PersistenceInstaller : IWindsorInstaller
{

    public void Install(IWindsorContainer container, IConfigurationStore store)
    {


        container.Register(

            //Nhibernate session factory
            Component.For<ISessionFactory>().UsingFactoryMethod(CreateNhSessionFactory).LifeStyle.Singleton,


            Component.For<ISession>().UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession()).LifestylePerWebRequest(),

            //All repoistories
            Classes.FromAssembly(Assembly.GetAssembly(typeof(HdtRepository))).InSameNamespaceAs<HdtRepository>().WithService.DefaultInterfaces().LifestyleTransient()




            );
    }

and my base repository looks like that:

  public abstract class RepositoryBase<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey> where TEntity : Entity<TPrimaryKey>
{

    /// <summary>
    /// Gets the NHibernate session object to perform database operations.
    /// </summary>
    public ISession Session { get; set; }


    /// <summary>
    /// Used to get a IQueryable that is used to retrive object from entire table.
    /// </summary>
    /// <returns>IQueryable to be used to select entities from database</returns>
    public IQueryable<TEntity> GetAll()
    {
        return Session.Query<TEntity>();
    }

    /// <summary>
    /// Gets an entity.
    /// </summary>
    /// <param name="key">Primary key of the entity to get</param>
    /// <returns>Entity</returns>
    public TEntity Get(TPrimaryKey key)
    {
        return Session.Get<TEntity>(key);
    }

    /// <summary>
    /// Inserts a new entity.
    /// </summary>
    /// <param name="entity">Entity</param>
    public void Insert(TEntity entity)
    {
        Session.Save(entity);
    }

    /// <summary>
    /// Updates an existing entity.
    /// </summary>
    /// <param name="entity">Entity</param>
    public void Update(TEntity entity)
    {
        Session.Update(entity);
    }

    /// <summary>
    /// Deletes an entity.
    /// </summary>
    /// <param name="id">Id of the entity</param>
    public void Delete(TPrimaryKey id)
    {
        Session.Delete(Session.Load<TEntity>(id));
    }
}

Everything works corret when I Insert a entity. Update is onyl working when I add a Session.Flush() to my Update method.

This is the mehtod which is called from Ajax and performs insert or update.

 [Authorize]
    [ValidateInput(false)]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public JsonNetResult CreateOrUpdateTimeRecord(TimeRecord tr)
    {

        TimeRecord trLocal;
        if (tr.Id == -1 || tr.Id == 0)
        {
            trLocal = new TimeRecord();

            trLocal.Description = tr.Description;
            trLocal.StartTime = tr.StartTime;
            trLocal.EndTime = tr.EndTime;

            trLocal.User = _userRepo.Get(tr.User.Id);
            trLocal.Hdt = _hdtRepo.Get(tr.Hdt.Id);

            _timeRepo.Insert(trLocal);
        }
        else
        {
            trLocal = _timeRepo.Get(tr.Id);

            trLocal.Description = tr.Description;
            trLocal.StartTime = tr.StartTime;
            trLocal.EndTime = tr.EndTime;

            _timeRepo.Update(trLocal);
        }



        return new JsonNetResult() { Data = trLocal};
    }

I dont understand why this works for insert and not for Update. Do I have to care about transaction and opening/closing Sessions? I thought that "LifestylePerWebRequest" would do that for me.

Cheers, Stefan

Was it helpful?

Solution

:edit: (my initial answer was partially wrong)

You implementation should actually work fine (just tested it). Though I can reproduce the behavior that updates are not flushed although the session object gets disposed correctly

The LifestylePerWebRequest actually takes care of that just fine, it will dispose the session whenever the request ends. Therefore you had to add the request handle to the web.config etc... So the windsor stuff is perfectly aware of the fact that ISession is disposable and that it has to dispose it...

This is because of the the FlushMode of the session.

The default mode is Auto, which might not be really what you want because you cannot rely on the changes getting stored (especially with update calls).

You can either change the FlushMode of the created session object, or, and this is what I recommend, use transactions.

Lets look at the following example:

var session = container.Resolve<ISession>();

var obj = new Paper()
{
    Author = "Author",
    Description = "Description",
};
session.Save(obj);

obj.Author = "Author2";
session.Update(obj);

In this case, the update will never be flushed/stored in the database. This is the behavior you currently have I guess.

Now lets add a transaction around it:

var session = container.Resolve<ISession>();
using (var transaction = session.BeginTransaction())
{
    var obj = new Paper()
    {
        Author = "Author",
        Description = "Description",
    };
    session.Save(obj);

    obj.Author = "Author2";
    session.Update(obj);

    transaction.Commit();
}

Now the changes will be saved for sure.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top