简体   繁体   中英

Concurrency issue with WCF and nHibernate

we have a WCF webservice handling some business entities. ORM is nhibernate 4.0.4, .NET 4.0. We are using an IDispatchMessageInspector to open a session and a transaction in AfterReceiveRequest, context class is wcf_operation:

public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
    if (!CurrentSessionContext.HasBind(this.factory))
    {
        this.log.Log.Debug("Creating NH Session");
        var session = this.factory.OpenSession();
        session.FlushMode = FlushMode.Never;
        session.BeginTransaction();
        CurrentSessionContext.Bind(session);
    }

    return null;
}

The transaction is committed and the session is closed in BeforeSendReply. This is working as long as only one call at a time deals with a specific entity.

If two concurrent webservice try to update the same entity, I get an nhibernate exception

NHibernate.HibernateException: Illegal attempt to associate a collection with two open sessions

As I understand that two updates collide on the database level, I do not understand the problem nhibernate has here. From my understanding, the two sessions of the two calls should be independent of each other; am I missing something here? A configuration maybe?

As said, I see the problem the database has; nevertheless, I would expect an exception claiming something about conccurent update or so. Since the traffic on the webservice grows, I fear that I have a general problem with my session handling.

This problem is not a concurrency issue. The issue is that you are using Sessions in a way they are not designed for.

When an entity object is loaded from the database, it belongs to the session that loaded it. The session holds an internal map of all of the objects it has loaded. It you try and make this session interact with an object loaded by a different session, it will recognise that the object is not in its internal map and throw an exception.

Keep in mind that a session follows the UnitOfWork design pattern. They are meant to be short lived. You create a session, read from the database, make changes, and then discard the session along with all of the in-memory objects.

NHibernate does provide a way to detach an object from a session and then attach it to a different session, but this approach would be fraught with danger in a concurrent environment. Instead, I suggest you modify your design so that the shared object is not an nHibernate entity but some kind of key reference to the entity, which can allow any separate session to reload it if needed.

If you feel that some objects really should stay in memory for the lifetime of your WCF service, you can make use of the nHibernate second-level cache. This blog entry explains the second-level cache quite well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM