Register | Login

Stacking Code

public interface IBlog { string Dump(Stream consciousness); }

Optimistic Concurrency and NHibernate

Thursday, 9 December, 2010 @ 8:33 PM < Adam Boddington
Tags: Architecture, ASP.NET, Building Neno, Concurrency Control, NHibernate

This is post #16 in the Building Neno series. Please click here for a description of the Building Neno project and instructions on how to access the source code for this post.

In my last post I waxed lyrical about the importance of optimistic concurrency. But is it actually working in my web application? Time to check.

A Tale of Two Screens

The only screen I have that lets me edit anything is the one I just created, the user profile screen. I'll temporarily make the version property visible for my testing and open up two screens to simulate two users modifying the same data.

Fail 1

Both have the same version number, as they should. I'll modify one to increment its version...

Fail 2

Now I'll modify the other screen and expect a stale object exception...

Fail 3

But instead I get another version increment. NHibernate has ignored the "1" I gave it, used the "2" it got from the re-retrieval, and incremented it to "3". Oh no... NHibernate, what is going on?!?

All Your Version Are Belong To Us

This isn't a "bug" as such. NHibernate just doesn't expect to be used this way, i.e. retrieving an object and changing its version. It thinks of version as a managed property, fundamental to the way caching and all that other hidden goodness inside of NHibernate works. Setting version doesn't really do anything because NHibernate already knows what the version is -- it's simply not listening when anyone tries to tell it different.

The problem has been noticed before and talked about at length in respect to both Hibernate and NHibernate.

There are two ways to make a version change "stick". One is to evict the object from NHibernate, which prevents NHibernate from knowing what the version should be and forces it to look in the version property instead. The other is perform a manual check on the version property in an NHibernate interceptor and throw a stale object exception from there. I've gone down the eviction route before and run into problems, so the solution I favour now is the interceptor.

Stale Interceptor

Luckily there's already some code in Moja to help build out interceptors. That's amazing! It's like I knew I would be making interceptors at some point...

namespace StackingCode.Moja.Repositories.NHibernate.Interceptors
{
    public class StaleInterceptor : Interceptor
    {
        public override bool OnUpdate(object entity, object id, IEnumerable<EntityPropertyForUpdate> properties)
        {
            CheckStaleness(entity, id);

            // No properties have changed, return false.
            return false;
        }

        public override bool OnDelete(object entity, object id, IEnumerable<EntityProperty> properties)
        {
            CheckStaleness(entity, id);

            // No properties have changed, return false.
            return false;
        }

        private void CheckStaleness(object entity, object id)
        {
            ISessionImplementor sessionImplementor = InterceptorAdapter.Session.GetSessionImplementation();
            IEntityPersister entityPersister = sessionImplementor.GetEntityPersister(null, entity);

            if (entityPersister.IsVersioned)
            {
                object version = entityPersister.GetVersion(entity, sessionImplementor.EntityMode);
                object currentVersion = entityPersister.GetCurrentVersion(id, sessionImplementor);

                if (!entityPersister.VersionType.IsEqual(version, currentVersion))
                    throw new StaleObjectStateException(entityPersister.EntityName, id);
            }
        }
    }
}

The staleness code is almost a straight copy from Stefan's example. Here I'm delving into the innards of NHibernate to get the version on the entity itself, and the current version according to NHibernate, and comparing the two. This is called right before any object is updated or deleted. Throwing an exception will prevent the update or delete from taking place.

Hooking the interceptor up to the session is just a small matter of configuring Spring a bit more...

<object name="Session" factory-object="SessionFactory" factory-method="OpenSession" scope="request">
    <constructor-arg>
        <list>
            <ref object="StaleInterceptor" />
        </list>
    </constructor-arg>
</object>
<object name="StaleInterceptor" type="StackingCode.Moja.Repositories.NHibernate.Interceptors.StaleInterceptor, StackingCode.Moja.Repositories.NHibernate" scope="request" />
<object name="SessionFactory" type="StackingCode.Moja.Repositories.NHibernate.SessionFactoryWrapper, StackingCode.Moja.Repositories.NHibernate" />

Intercept This

Going back to my two screens. If I update one...

Success 1

And then the other...

Success 2

Success! A stale object exception. What the user is supposed to do with it though... Well, that's a story for another day.

There are 0 comments.


Comments

Leave a Comment

Please register or login to leave a comment.


Older
User Profile

Newer
Validation with NHibernate and Data Annotations

Older
User Profile

Newer
Validation with NHibernate and Data Annotations

browse with Pivot


About


Projects

Building Neno


RSS
Recent Posts

Codility Nitrogenium Challenge
OS X Lock
HACT '13
Codility Challenges
Priority Queue


Tags

Architecture (13)
ASP.NET (2)
ASP.NET MVC (13)
Brisbane Flood (1)
Building Neno (38)
C# (4)
Challenges (3)
Collections (1)
Communicator (1)
Concurrency Control (2)
Configuration (1)
CSS (5)
DataAnnotations (2)
Database (1)
DotNetOpenAuth (2)
Entity Framework (1)
FluentNHibernate (2)
Inversion of Control (5)
JavaScript (1)
jQuery (4)
Kata (2)
Linq (7)
Markdown (4)
Mercurial (5)
NHibernate (20)
Ninject (2)
OpenID (3)
OS X (1)
Pivot (6)
PowerShell (8)
Prettify (2)
RSS (1)
Spring (3)
SQL Server (5)
T-SQL (2)
Validation (2)
Vim (1)
Visual Studio (2)
Windows Forms (3)
Windows Service (1)


Archives


Powered by Neno, ASP.NET MVC, NHibernate, and small furry mammals. Copyright 2010 - 2011 Adam Boddington.
Version 1.0 Alpha (d9e7e4b68c07), Build Date Sunday, 30 January, 2011 @ 11:37 AM