/// <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> protected virtual void UpgradeLock(object entity, EntityEntry entry, LockMode requestedLockMode, ISessionImplementor source) { 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(string.Format("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 = persister.Cache.Lock(ck, entry.Version); } else { ck = null; slock = null; } try { if (persister.IsVersioned && requestedLockMode == LockMode.Force) { // todo : should we check the current isolation mode explicitly? object nextVersion = persister.ForceVersionIncrement(entry.Id, entry.Version, source); entry.ForceLocked(entity, nextVersion); } else { persister.Lock(entry.Id, entry.Version, entity, requestedLockMode, source); } 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) { persister.Cache.Release(ck, slock); } } } }