0

In my web application, somewhere during request cycle I call following method on repository:

     repository.Delete(objectToDelete);   

and this is NHibernate implementation:

    public void Delete(T entity)
    {
        if (!session.Transaction.IsActive)
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Delete(entity);
                transaction.Commit();
            }
        }
        else
        {
            session.Delete(entity);
        }
    }

And session.Delete(entity) (inside using statement) fails - which is fine cos I have some database constraints and this is what I expected. However, at the end of the request in Global.asax.cs I close the session with following code:

    protected void Application_EndRequest(object sender, EventArgs e)
    {
        ISession session = ManagedWebSessionContext.Unbind(HttpContext.Current, sessionFactory);

        if (session != null)
        {
            if (session.Transaction != null && session.Transaction.IsActive)
            {
                session.Transaction.Rollback();
            }
            else
            {
                session.Flush();
            }
            session.Close();
        }
    }

This is the same session that was used to delete the object. And now, when:

session.Flush();

is called, NHibernate tries to perform the same DELETE operation - that throws exception and application crushes. Not exactly what I wanted, as I have already handled exception before (on repository level) and I show preety UI message box.

How can I prevent NHibernate from trying to perform DELETE (and I guess UPDATE operation in other scenarios) action once again when that session.Flush is called. Basicall I haven't designed that Application_EndRequest so I'm not sure whether it's a good approach to Flush everything.

Thanks

dragonfly
  • 17,407
  • 30
  • 110
  • 219

1 Answers1

1

The flush-mode of NHibernate is by default set to 'auto', which means (amongst other things) that committing the transaction will cause NHibernate to flush and the delete fails.

At the end of the request you manually flush the session again, telling NHibernate to do the delete again (since there is no active transaction).

The reason that this is not working as expected, is because your expectations are wrong. A NHibernate session is a unit of work, i.e. everything your application does in one request. Transactions are completely unrelated. The fact that flushing the session fails the first time, is also the reason that it fails the second time.

If you want to prevent NHibernate to perform the delete a second time, you shouldn't flush twice, only once. Either by committing the transaction or by doing it manually.

On a somewhat unrelated note: you are using NHibernate and transactions wrong. It will give you massive problems later on. There are some good resources online about how to use NHibernate in a web application.

Jeroen
  • 979
  • 1
  • 7
  • 16
  • Thanks. Anyway, what I'm doing wrong? Actually session-pre-request + transaction/session support code is taken from NHibernate 3 book. – dragonfly Jul 17 '12 at 12:58
  • Session-per-request is fine, but flushing the session manually in the EndRequest (and not be in a transaction) isn't. Transaction-per-operation is also not recommended. Starting and committing transactions should be done at the place where all the transactional code in between should either all succeed or all fail. – Jeroen Jul 17 '12 at 13:06
  • Like I said: Application_End request wasn't written by me, it already was there - was, because I've commented it out :) Transaction-per-operation is not recommended? Do you have any resources on that? Appart from it, I still can open transaction explicitly outside operation method (if (!session.Transaction.IsActive)) and keep it open and commit/rollback how I want. So if I need a few operations to be in the same transaction, I can do it. Otherwise, I just go with default transaction inside repository Add/Remove/Update methods - like suggested in NHibernate 3 book. Thanks – dragonfly Jul 17 '12 at 13:10
  • Commenting out bad code is always a good thing ;-). Take a look here: http://ayende.com/blog/3442/how-to-review-nhibernate-application. _"Transactions should be opened at the service boundary"_ – Jeroen Jul 17 '12 at 13:27
  • Thanks :) I also have an assembly of Service like classes that do the transactions management - it's a mixture of Layer Supertype & Service Layer from http://martinfowler.com/eaaCatalog/index.html . Thanks for tips! – dragonfly Jul 17 '12 at 13:38