private void CheckEntityLock(DbContext writableContext, IList <Guid> lockedIds) { foreach ( var updatedEntityEntry in writableContext.ChangeTracker.Entries <EntityIdentifierBase>().Where(x => x.State == EntityState.Modified)) { EntityLockResult lockResult = null; if (updatedEntityEntry.Entity is ILockable) { lockResult = lockingManager.IsLockedBy(updatedEntityEntry.Entity); } var versionedEntity = updatedEntityEntry.Entity as IVersionedVolume; if (versionedEntity != null) { lockResult = lockingManager.IsLockedBy(versionedEntity.UnificRootId); } if (lockResult != null) { switch (lockResult.LockStatus) { case EntityLockEnum.Unlocked: continue; case EntityLockEnum.LockedForCurrent: lockedIds.Add(versionedEntity.UnificRootId); break; default: throw new LockException("", new List <string> { lockResult.LockedBy }); } } } }
/// <summary> /// Push changes done in context into database /// </summary> /// <param name="saveMode"></param> /// <param name="parentEntity">Logical parent entity to mark as updated when committing changes to database</param> /// <param name="userName">The user name for user. Used in console application (PTV.DataMapper.ConsoleApp) where there is no Httpcontext</param> public void Save(SaveMode saveMode = SaveMode.Normal, object parentEntity = null, string userName = null) { IList <VmLogEntry> logEntries = new List <VmLogEntry>(); IList <Guid> lockedIds = new List <Guid>(); var writableContext = this.DbContext as DbContext; logger.LogDebug("*** Before detect changes of entities ***"); CreateLogs(writableContext); // writableContext.ChangeTracker.Entries().ToList().Where(i => i.Properties.Any(m => m.IsModified)).SelectMany(e => e.Properties.Where(m => m.IsModified && (m.OriginalValue?.ToString() == m.CurrentValue?.ToString()))).ForEach(e => e.IsModified = false); // // // var allEntries = writableContext.ChangeTracker.Entries().ToList().Where(i => i.State == EntityState.Modified || i.Properties.Any(m => m.IsModified || (m.OriginalValue?.ToString() != m.CurrentValue?.ToString()))); // allEntries.ForEach(e => // { // var propertiesStatuses = e.Properties.Select(p => $"{p.Metadata.Name} is modified: {p.IsModified}, original: {p.OriginalValue}, new value: {p.CurrentValue}").ToList(); // Console.WriteLine($"{e.Metadata.Name} is {e.State}"); // propertiesStatuses.ForEach(p => // { // Console.WriteLine($" - {p}"); // }); // }); writableContext.ChangeTracker.DetectChanges(); logger.LogDebug("*** After detect changes of entities ***"); CreateLogs(writableContext); userName = GetUserNameForAuditing(saveMode, userName); if (!string.IsNullOrEmpty(userName) || saveMode == SaveMode.NonTrackedDataMigration) { if (saveMode != SaveMode.NonTrackedDataMigration) { if (parentEntity != null && writableContext.ChangeTracker.Entries <IAuditing>().Any(x => x.State == EntityState.Added || x.State == EntityState.Modified)) { writableContext.Entry(parentEntity).Property("Modified").IsModified = true; writableContext.Entry(parentEntity).Property("ModifiedBy").IsModified = true; } if (saveMode != SaveMode.AllowAnonymous) { CheckRoles(saveMode, writableContext); CheckEntityLock(writableContext, lockedIds); } } var dateToSave = DateTime.UtcNow; var operationId = dateToSave.ToString("O") + "-" + Guid.NewGuid(); foreach (var updatedEntityEntry in writableContext.ChangeTracker.Entries <IAuditing>().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified)) { ApplyFormattingToPropertiess(updatedEntityEntry); SetAuditingFields(updatedEntityEntry, userName, dateToSave, saveMode); SetOperationInfoFields(updatedEntityEntry, operationId, dateToSave); logEntries.Add(GetLogEntry(updatedEntityEntry.Entity)); } } else { throw new Exception(CoreMessages.AnonymousSaveNotAllowed); } // unlock all entries var lockResults = lockingManager.UnLockEntities(this, lockedIds); EntityLockResult lockedEntity = lockResults.Values.FirstOrDefault(i => i.LockStatus != EntityLockEnum.Unlocked); if (lockedEntity != null) { throw new LockException("", new List <string>() { lockedEntity.LockedBy }); } // save changes writableContext.SaveChanges(); // Let's add the log entries only when we are sure database changes have been successfully saved into database. logger.LogDBEntries(logEntries); }