I am working on a large application that manages complex 'events' with quite a bit of data.
The application is broken into a client (C# mainly .NET 2.0 mainly), a WCF based server made to run on IIS (web services at this layer), and a data back end that is NHibernate based with an MS SQL Server database backend.
We are encountering a bug with the follow scenario:
Multiple users (in this case 6, in our testing) simultaneously save a persisted object (such as an event) on the client. (This is done via a verbal countdown, so we're talking a second or so difference due to reaction times)
When they save objects on the client, the client calls the server to save that object. The server does any business logic required, and then commits the change via NHibernate.
In this situation (multiple saves over service calls) some clients will come back with an unhanded exception:
"Row was updated or deleted by another transaction"
Which is an NHibernate exception.
In my research I found some instances of this error, but it was always sequential. Our application is fine sequentially, this only happens with simultaneous saves.
How should multiple simultaneous NHibernate transactions be protected from each other?
(This is going to be a high volume application, so minimal needed locking is good. We can't afford to lock all saves generally.)
Are there NHibernate settings that would do this? Do we need to figure out some server code side locking before hand? Can the database handle this with perhaps with different transaction protection settings?
This is a bear to test, like most threading issues, hence the research/theory approach. What is the experience with an architecture like this?
Edit: Further information and a theory.
It seems that changing values that are directly in the table as the main entity did not cause this problem, while changing elements that are accessed through a join did. (In this case a set of attributes).
Our working theory that seems to fit this situation is the following:
Multiple saves come in for the same event. Each one gets a copy of the existing event (to modify). The first ones to save are OK. The later ones, however, have updates such as the addition or deletion of attributes (which are a join table) and discover that the add or delete that needs done has already been done, and bails out because another transaction edited the event.
How should we keep these events in sync?