Great Nicolás!  I was about to suggest you that Lock().Upgrade() when I got
your successful feedback :)



2016-04-17 18:50 GMT-03:00 Nicolás Mancilla <
[email protected]>:

> I solved my problem.
>
> Previously I used session.Lock(entity, LockMode.Upgrade);, but that throws
> an StaleObjectStateException, but instead, if I used
> session.QueryOver<POCO>().Lock().Upgrade...; it works fine. I suppose that
> the lock was set to late in the first case, so the exception was thrown.
>
> Thanks again for everything :).
>
> El domingo, 17 de abril de 2016, 9:46:39 (UTC-3), Quicoli escribió:
>>
>> Hi,
>>
>> I believe getlastunusedfolio should lock your table and  your transction
>> scope should be something like lock and wait.
>>
>> This way the first one in,  lock the access and the subsequent requests
>> keep waiting for the first one to finish...
>>
>> This is an idea...
>> Em 17/04/2016 07:18, "Nicolás Mancilla" <[email protected]>
>> escreveu:
>>
>>> 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.
>>>
>> --
> 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.
>

-- 
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