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.