/// <summary> /// Performs a pessimistic lock upgrade on a given entity, if needed. /// </summary> /// <param name="entity">The entity for which to upgrade the lock.</param> /// <param name="entry">The entity's EntityEntry instance.</param> /// <param name="requestedLockMode">The lock mode being requested for locking. </param> /// <param name="source">The session which is the source of the event being processed.</param> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param> protected virtual async Task UpgradeLockAsync(object entity, EntityEntry entry, LockMode requestedLockMode, ISessionImplementor source, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (requestedLockMode.GreaterThan(entry.LockMode)) { // The user requested a "greater" (i.e. more restrictive) form of // pessimistic lock if (entry.Status != Status.Loaded) { throw new ObjectDeletedException("attempted to lock a deleted instance", entry.Id, entry.EntityName); } IEntityPersister persister = entry.Persister; if (log.IsDebugEnabled()) { log.Debug("locking {0} in mode: {1}", MessageHelper.InfoString(persister, entry.Id, source.Factory), requestedLockMode); } ISoftLock slock; CacheKey ck; if (persister.HasCache) { ck = source.GenerateCacheKey(entry.Id, persister.IdentifierType, persister.RootEntityName); slock = await(persister.Cache.LockAsync(ck, entry.Version, cancellationToken)).ConfigureAwait(false); } else { ck = null; slock = null; } try { if (persister.IsVersioned && requestedLockMode == LockMode.Force) { // todo : should we check the current isolation mode explicitly? object nextVersion = await(persister.ForceVersionIncrementAsync(entry.Id, entry.Version, source, cancellationToken)).ConfigureAwait(false); entry.ForceLocked(entity, nextVersion); } else { await(persister.LockAsync(entry.Id, entry.Version, entity, requestedLockMode, source, cancellationToken)).ConfigureAwait(false); } entry.LockMode = requestedLockMode; } finally { // the database now holds a lock + the object is flushed from the cache, // so release the soft lock if (persister.HasCache) { await(persister.Cache.ReleaseAsync(ck, slock, cancellationToken)).ConfigureAwait(false); } } } }