0

I am writing project and using NHibernate 3.1

SimpleTest:

        IUserRepository userRepository = new UserRepository(SessionFactory);
        var admin = userRepository.GetByName("admin");
        admin.Profile.Signature = "Signature";
        userRepository.Update(admin);

Implementation Repository.Update():

public virtual void Update(TEntity entity)
{
    if (!session.Transaction.IsActive)
    {
        TResult result;
        using (var tx = session.BeginTransaction())
        {
            session.SaveOrUpdate(entity)
            tx.Commit();
        }
        return result;
    }
    session.SaveOrUpdate(entity)
}

You must not confuse the call session.SaveOrUpdate (entity) in the branch else, because it is necessary if the Update called in an external transaction.

  • First, I receive admin with Version = 1. His state is persistent.
  • I change the value of any property.
  • I do update.
  • When the flow reaches the line tx.Commit();, NHibernate generates a query:

    UPDATE Users SET Version = 2, Name = 'admin', EncryptedPassword = '21232f297a57a5a743894a0e4a801fc3', EMail = 'admin@admin.com', IsActivated = 1, IsBanned = 0, CommentsNumber = 0, Role = 'Admin', FirstName = 'Alexey', LastName = 'Kovpaev', DateOfBirth = '1992-01-02T12:00:00.00', About = 'Just admin', Signature = 'Signature' WHERE UserId = 'e23056df-d934-4880-b6b8-f2128cd41504' AND Version = 1

  • NHibernate throws an exception: NHibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)

It also does not work and leads to the same exception:

    using (var tx = Session.BeginTransaction())
    {
        var admin = Session.CreateCriteria<User>().Add(Restrictions.Eq("Name", "admin")).UniqueResult<User>();
        admin.Profile.Signature = "Signature";
        Session.SaveOrUpdate(admin);
        tx.Commit();
    }

First, the version numbers are correct. Second, other transactions just did not exist.

Why?

Kovpaev Alexey
  • 1,725
  • 6
  • 19
  • 38

1 Answers1

0

I've found two sources claiming that NHibernate doesn't support nested transactions. The suggested solution seems to be Ayendes UnitOfWork implementation or nest your transactions in a TransactionScope.

How do I do nested transactions in NHibernate?

Achieving NHibernate Nested Transactions Behavior

Community
  • 1
  • 1
Gaute Løken
  • 7,522
  • 3
  • 20
  • 38
  • in this code, there is no nested transactions. And more than one level of nesting can not be, because it is checked in the block "if". – Kovpaev Alexey Nov 05 '11 at 11:41
  • I didn't read your code correctly. You're expressly making sure there is no nesting. Ok. I wonder about your UserRepository. How does it manage sessions? Will GetByName open and close a session internally or do you keep one session open for the lifetime of the UserRepository? – Gaute Løken Nov 05 '11 at 13:21
  • This code from the unit-tests and there is a very simple session management. It creates one session, and working with it all tests. At the moment of rise of the exception session has only one persistent entity. It is the admin, with the correct id and version. – Kovpaev Alexey Nov 05 '11 at 13:42
  • Are you using MSTest and have other unit tests also running? MSTest will run your tests in parallell, so you need to do locking to ensure that two tests don't use the session concurrently. If this is your only test or you're not using a testing framework that runs tests in parallell, I'm out of ideas. – Gaute Løken Nov 05 '11 at 14:39
  • it is very nice, that at least someone wants to help) I'm using NUnit, and run this test apart from others, so this should be no problem. I think I am missing some obvious detail, and people with experience should quickly see it, but because I am using NHibernate for the first time I can not find it. – Kovpaev Alexey Nov 05 '11 at 16:02