Hello Everyone!

I have a question regarding concurrent requests.

I have an two entities:

class Document {

FolioNumber // Long/bigint
other_properties...

}

class FolioRange {

CurrentFolio // Long/bigint
Start // The first folio in the range
End // The last folio in the range
IsUsed // When the CurrentFolio >= End
DateCreated
IsCurrentRange

DocumentType
RangeStatus 

}

(Imagine that these are valid POCOs please :) 

Every time a Document is inserted to the database, the Document.FolioNumber 
is set to the FolioRange.CurrentFolio. The logic is this:

public long GetNextFolioNumber(string documentType, Tenant tenant)
        {
            // Check if there is a folio range defined
            var entity = session.QueryOver<FolioRange>()
                .Where(
                    i =>
                        i.Tenant.Id == tenant.Id && i.DocumentType == 
documentType && i.IsCurrentRange &&
                        i.Status == RangeStatus.Enabled)
                .Take(1)
                .SingleOrDefault();
            if (entity == null)
            {
                return 0;
            }
 
            // Retrieve an unused folio, if there are any
            var folio = GetLastUnusedFolio(entity);
            if (folio > 0)
            {
                return folio;
            }
 
            FolioRange range;
 
            // If the folio range has no folios left,
            // try to change to the newest folio range
            if (entity.IsUsed)
            {
                log.InfoFormat(
                    "The folio range '{0}' has been consumed. Trying to switch 
to the next one (if there is one).",
                    entity.Id);
                // Update the old folio range to disable it
                entity.IsCurrentRange = false;
                entity.Status = RangeStatus.Disabled;
                session.Update(entity);
                range = session.QueryOver<FolioRange>()
                    .Where(
                        i =>
                            i.Tenant.Id == tenant.Id && i.DocumentType == 
documentType &&
                            i.CreatedDate > entity.CreatedDate)
                    .Take(1)
                    .SingleOrDefault();
 
                // If there is no newest folio range, return
                if (range == null)
                {
                    return 0;
                }
 
                log.InfoFormat("Successfully switched to folio range '{0}'.", 
entity.Id);
                // If there was a newest folio range, update it.
                range.IsCurrentRange = true;
                range.Status = RangeStatus.Enabled;
            }
            else
            {
                log.InfoFormat("Using folio range '{0}'; Current folio: {1}", 
entity.Id, entity.CurrentFolio);
                range = entity;
            }
 
            // Set the current folio as result and increment the current folio.
            folio = range.CurrentFolio;
            range.CurrentFolio++;
            session.Update(range);
            return folio;
        }


This works well when there is only 1 request, but when there are more than 1, 
then there is a race condition when the range.CurrentFolio++ is not updated and 
two Documents get created with the same folio number, which is not allowed.


I've tried using session.Lock(range, LockMode.Upgrade), without luck (a UNIQUE 
KEY Violation is triggered). The Session.Transaction isolation level is 
ReadCommited.


I'm using NHibernate 4.0.4 and Nancy 1.4.3.


Any suggestions, book references or any reading will be greatly appreciated.


Thanks!

-- 
You received this message because you are subscribed to the Google Groups 
"nhusers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/nhusers.
For more options, visit https://groups.google.com/d/optout.

Reply via email to