607 lines
28 KiB
C#
607 lines
28 KiB
C#
namespace EnVisage
|
|
{
|
|
using Code;
|
|
using Code.Integration;
|
|
using Code.ThreadedProcessing;
|
|
using Code.BLL;
|
|
using Models.Entities;
|
|
using NLog;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.Entity;
|
|
using System.Data.Entity.Core.EntityClient;
|
|
using System.Data.Entity.Core.Objects;
|
|
using System.Data.Entity.Infrastructure;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using System.Web;
|
|
using static Code.AuditProxy;
|
|
|
|
public partial class EnVisageEntities //: DbContext
|
|
{
|
|
#region Private Variables
|
|
|
|
private readonly Logger _Logger = LogManager.GetCurrentClassLogger();
|
|
|
|
#endregion
|
|
|
|
#region Private Classes
|
|
|
|
private class TransactionInformation
|
|
{
|
|
public bool IsLocalTransaction { get; set; }
|
|
public string TransactionId { get; set; }
|
|
public string ExecutorId { get; set; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
|
|
public EnVisageEntities(string sConnectionString) : base(sConnectionString)
|
|
{
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
public static EnVisageEntities PrevuEntity(string sConnectionString, bool isAdo)
|
|
{
|
|
if (isAdo)
|
|
{
|
|
var entityBuilder = new EntityConnectionStringBuilder
|
|
{
|
|
Provider = "System.Data.SqlClient",
|
|
ProviderConnectionString = sConnectionString,
|
|
Metadata = @"res://*/DataModel.csdl|res://*/DataModel.ssdl|res://*/DataModel.msl"
|
|
};
|
|
sConnectionString = entityBuilder.ConnectionString;
|
|
}
|
|
return new EnVisageEntities(sConnectionString);
|
|
}
|
|
|
|
public ObjectContext ObjectContext()
|
|
{
|
|
return (this as IObjectContextAdapter).ObjectContext;
|
|
}
|
|
|
|
public override int SaveChanges()
|
|
{
|
|
var trackChangesTransaction = TrackChanges();
|
|
var result = base.SaveChanges();
|
|
|
|
if (trackChangesTransaction.IsLocalTransaction)
|
|
Task.Run(() => CommitHistoryChanges(trackChangesTransaction.TransactionId, trackChangesTransaction.ExecutorId));
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>Performs bulk save changes with history tracking</summary>
|
|
public void ExecuteBulkSaveChanges()
|
|
{
|
|
var trackChangesTransaction = TrackChanges();
|
|
|
|
this.BulkSaveChanges();
|
|
|
|
if (trackChangesTransaction.IsLocalTransaction)
|
|
Task.Run(() => CommitHistoryChanges(trackChangesTransaction.TransactionId, trackChangesTransaction.ExecutorId));
|
|
}
|
|
|
|
#region Private Methods
|
|
|
|
/// <summary>Sets timestamps for created and changed entities as well as for their parent container entities</summary>
|
|
private void SetTimestamps()
|
|
{
|
|
var stateManager = ObjectContext().ObjectStateManager;
|
|
var addedEntities = stateManager.GetObjectStateEntries(EntityState.Added);
|
|
var modifiedEntities = stateManager.GetObjectStateEntries(EntityState.Modified);
|
|
var removedEntities = stateManager.GetObjectStateEntries(EntityState.Deleted);
|
|
|
|
addedEntities.Where(x => x.Entity is ITimestampEntity).ToList().ForEach(t =>
|
|
{
|
|
var timestampEntity = t.Entity as ITimestampEntity;
|
|
timestampEntity?.SetCreatedTimestamp();
|
|
});
|
|
modifiedEntities.Where(x => x.Entity is ITimestampEntity).ToList().ForEach(t => (t.Entity as ITimestampEntity).SetUpdatedTimestamp());
|
|
|
|
#region Update scenario timestamps by relations
|
|
|
|
int modifiedCount = modifiedEntities.Count();
|
|
int addedCount = addedEntities.Count();
|
|
int removedCount = removedEntities.Count();
|
|
|
|
if ((modifiedCount > 0) || (addedCount > 0) || (removedCount > 0))
|
|
{
|
|
List<ObjectStateEntry> allChangedEntities = new List<ObjectStateEntry>(modifiedCount + addedCount + removedCount);
|
|
allChangedEntities.AddRange(addedEntities);
|
|
allChangedEntities.AddRange(modifiedEntities);
|
|
allChangedEntities.AddRange(removedEntities);
|
|
|
|
List<Guid> changedScenarios = GetScenarios(allChangedEntities);
|
|
|
|
if (changedScenarios.Count > 0)
|
|
{
|
|
// Exclude recently created scenarios
|
|
List<Guid> excludableScenarios =
|
|
addedEntities.Where(x => x.Entity is Scenario).Select(x => (x.Entity as Scenario).Id).ToList();
|
|
Scenarios.Where(x => !excludableScenarios.Contains(x.Id) && changedScenarios.Contains(x.Id))
|
|
.ToList()
|
|
.ForEach(s => s.SetUpdatedTimestamp());
|
|
}
|
|
|
|
allChangedEntities = null;
|
|
addedEntities = null;
|
|
modifiedEntities = null;
|
|
removedEntities = null;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
private List<Guid> GetScenarios(List<ObjectStateEntry> changedOrCreatedItems)
|
|
{
|
|
List<Guid> scenarios = new List<Guid>();
|
|
|
|
if ((changedOrCreatedItems == null) || (changedOrCreatedItems.Count < 1))
|
|
return scenarios;
|
|
|
|
scenarios.AddRange(
|
|
changedOrCreatedItems.Where(x =>
|
|
(x.Entity is ScenarioDetail) && (x.Entity as ScenarioDetail).ParentID.HasValue &&
|
|
!(x.Entity as ScenarioDetail).ParentID.Value.Equals(Guid.Empty))
|
|
.Select(t => (t.Entity as ScenarioDetail).ParentID.Value));
|
|
|
|
scenarios.AddRange(
|
|
changedOrCreatedItems.Where(x =>
|
|
(x.Entity is TeamAllocation) && !(x.Entity as TeamAllocation).ScenarioId.Equals(Guid.Empty))
|
|
.Select(t => (t.Entity as TeamAllocation).ScenarioId));
|
|
|
|
scenarios.AddRange(
|
|
changedOrCreatedItems.Where(x =>
|
|
(x.Entity is PeopleResourceAllocation) &&
|
|
!(x.Entity as PeopleResourceAllocation).ScenarioId.Equals(Guid.Empty))
|
|
.Select(t => (t.Entity as PeopleResourceAllocation).ScenarioId));
|
|
|
|
scenarios.AddRange(
|
|
changedOrCreatedItems.Where(x =>
|
|
(x.Entity is CostSaving) &&
|
|
!(x.Entity as CostSaving).ScenarioId.Equals(Guid.Empty))
|
|
.Select(t => (t.Entity as CostSaving).ScenarioId));
|
|
|
|
scenarios.AddRange(
|
|
changedOrCreatedItems.Where(x =>
|
|
(x.Entity is Rate) && (x.Entity as Rate).ParentId.HasValue &&
|
|
!(x.Entity as Rate).ParentId.Value.Equals(Guid.Empty) &&
|
|
!(x.Entity as Rate).ParentId.Value.Equals((x.Entity as Rate).ExpenditureCategoryId))
|
|
.Select(t => (t.Entity as Rate).ParentId.Value));
|
|
|
|
// For rates now return all the parents (not only scenarios)
|
|
scenarios.AddRange(
|
|
changedOrCreatedItems.Where(x =>
|
|
(x.Entity is Note) && (x.Entity as Note).ParentId.HasValue &&
|
|
!(x.Entity as Note).ParentId.Value.Equals(Guid.Empty))
|
|
.Select(t => (t.Entity as Note).ParentId.Value));
|
|
|
|
return scenarios.Distinct().ToList();
|
|
}
|
|
|
|
private void PushUpdates(IEnumerable<ObjectStateEntry> entries)
|
|
{
|
|
if (entries == null || !entries.Any())
|
|
return;
|
|
|
|
var trackingEntries = entries.Where(x => !x.IsRelationship && x.Entity != null &&
|
|
(x.Entity is Scenario || x.Entity is ScenarioDetail || x.Entity is Project))
|
|
.ToArray();
|
|
var changedScenarios = trackingEntries.Where(x => x.Entity is Scenario)
|
|
.Select(x => (x.Entity as Scenario)).ToList();
|
|
var changedScenariosIds = changedScenarios.Select(x => x.Id);
|
|
var changedScenariosViaDetailsIds = trackingEntries.Where(x => x.Entity is ScenarioDetail)
|
|
.Where(x => (x.Entity as ScenarioDetail).ParentID.HasValue)
|
|
.Select(x => (x.Entity as ScenarioDetail).ParentID.Value)
|
|
.Distinct();
|
|
var changedScenariosViaDetails = changedScenariosViaDetailsIds.Any() ? Scenarios.AsNoTracking()
|
|
.Where(x => x.Status == (int)ScenarioStatus.Active &&
|
|
!changedScenariosIds.Contains(x.Id) &&
|
|
changedScenariosViaDetailsIds.Contains(x.Id))
|
|
.ToList() : new List<Scenario>();
|
|
if (changedScenariosViaDetails.Any())
|
|
changedScenarios.AddRange(changedScenariosViaDetails);
|
|
|
|
var changedProjects = trackingEntries.Where(x => x.Entity is Project)
|
|
.Select(x => (x.Entity as Project)).ToList();
|
|
var changedProjectsIds = changedProjects.Select(x => x.Id);
|
|
var changedProjectsViaScenariosIds = changedScenarios.Where(x => x.ParentId.HasValue)
|
|
.Select(x => x.ParentId.Value)
|
|
.Distinct();
|
|
var changedProjectsViaScenarios = changedProjectsViaScenariosIds.Any() ? Projects.AsNoTracking()
|
|
.Where(x => !changedProjectsIds.Contains(x.Id) &&
|
|
changedProjectsViaScenariosIds.Contains(x.Id))
|
|
.ToList() : new List<Project>();
|
|
if (changedProjectsViaScenarios.Any())
|
|
changedProjects.AddRange(changedProjectsViaScenarios);
|
|
|
|
var parentProjectsIds = changedProjects.Where(x => x.ParentProjectId.HasValue)
|
|
.Select(x => x.ParentProjectId.Value)
|
|
.Distinct();
|
|
var parentProjects = parentProjectsIds.Any() ? Projects.AsNoTracking()
|
|
.Where(x => !changedProjectsIds.Contains(x.Id) &&
|
|
!changedProjectsViaScenariosIds.Contains(x.Id) &&
|
|
parentProjectsIds.Contains(x.Id))
|
|
.ToList() : new List<Project>();
|
|
if (parentProjects.Any())
|
|
changedProjects.AddRange(parentProjects);
|
|
|
|
var requiredStatuses = changedProjects.Select(x => x.StatusId).Distinct();
|
|
var statusesDict = requiredStatuses.Any() ? Status.Where(x => requiredStatuses.Contains(x.Id)).ToArray().ToDictionary(x => x.Id) : new Dictionary<Guid, Status>();
|
|
|
|
var requiredTypes = changedProjects.Select(x => x.TypeId).Distinct();
|
|
var typesDict = requiredTypes.Any() ? Types.Where(x => requiredTypes.Contains(x.Id)).ToArray().ToDictionary(x => x.Id) : new Dictionary<Guid, Type>();
|
|
|
|
var changedScenariosDict = changedScenarios.ToDictionary(x => x.Id);
|
|
var changedProjectsDict = changedProjects.ToDictionary(x => x.Id);
|
|
|
|
foreach (var entry in trackingEntries)
|
|
{
|
|
var captureForNotification = false;
|
|
Project project = null;
|
|
Scenario scenario = null;
|
|
Status _status = null;
|
|
Type _type = null;
|
|
|
|
if (entry.Entity is ScenarioDetail)
|
|
{
|
|
var scenarioDetail = entry.Entity as ScenarioDetail;
|
|
if (scenarioDetail.ParentID.HasValue && changedScenariosDict.ContainsKey(scenarioDetail.ParentID.Value))
|
|
scenario = changedScenariosDict[scenarioDetail.ParentID.Value];
|
|
if (scenario == null)
|
|
return;
|
|
|
|
if (scenario.Type == (int)ScenarioType.Portfolio && scenario.ParentId.HasValue)
|
|
if (changedProjectsDict.ContainsKey(scenario.ParentId.Value))
|
|
project = changedProjectsDict[scenario.ParentId.Value];
|
|
}
|
|
else if (entry.Entity is Scenario)
|
|
{
|
|
scenario = entry.Entity as Scenario;
|
|
if (scenario.Type == (int)ScenarioType.Portfolio && scenario.ParentId.HasValue)
|
|
if (changedProjectsDict.ContainsKey(scenario.ParentId.Value))
|
|
project = changedProjectsDict[scenario.ParentId.Value];
|
|
}
|
|
else if (entry.Entity is Project)
|
|
{
|
|
var projectId = (entry.Entity as Project).Id;
|
|
if (changedProjectsDict.ContainsKey(projectId))
|
|
project = changedProjectsDict[projectId];
|
|
}
|
|
if (project != null)
|
|
{
|
|
_status = statusesDict.ContainsKey(project.StatusId) ? statusesDict[project.StatusId] : null;
|
|
_type = typesDict.ContainsKey(project.TypeId) ? typesDict[project.TypeId] : null;
|
|
if (_status != null && _status.Id != Guid.Empty && _type != null && _type.Id != Guid.Empty)
|
|
{
|
|
if (_status.NotifyOnProjectDelete.HasValue)
|
|
if (_status.NotifyOnProjectDelete.Value)
|
|
captureForNotification = true;
|
|
if (_status.NotifyOnProjectCreate.HasValue)
|
|
if (_status.NotifyOnProjectCreate.Value)
|
|
captureForNotification = true;
|
|
if (_status.NotifyOnProjectChange.HasValue)
|
|
if (_status.NotifyOnProjectChange.Value)
|
|
captureForNotification = true;
|
|
if (_type.NotifyOnProjectDelete.HasValue)
|
|
if (_type.NotifyOnProjectDelete.Value)
|
|
captureForNotification = true;
|
|
if (_type.NotifyOnProjectCreate.HasValue)
|
|
if (_type.NotifyOnProjectCreate.Value)
|
|
captureForNotification = true;
|
|
if (_type.NotifyOnProjectChange.HasValue)
|
|
if (_type.NotifyOnProjectChange.Value)
|
|
captureForNotification = true;
|
|
}
|
|
}
|
|
// if we are not capturing data, and the scenario is not active we do not
|
|
// do any push changes.
|
|
if (entry.Entity is Scenario || entry.Entity is ScenarioDetail)
|
|
if (!captureForNotification)
|
|
return;
|
|
|
|
string action = entry.State == EntityState.Added ? "Add" : "Update";
|
|
_Logger.Log(LogLevel.Debug, "CRM " + action + " for " + (entry.Entity is Scenario ? "Scenario" : "Project"));
|
|
var crmDal = IntergrationHelper.GetIntergrationClass(IntergrationAccessType.ProjectExport, null);
|
|
Dictionary<string, Dictionary<string, string>> pushToCrmCollection = new Dictionary<string, Dictionary<string, string>>();
|
|
string tableName = entry.Entity.GetType().Name.Split('_')[0];
|
|
Dictionary<string, string> colcollection = new Dictionary<string, string>();
|
|
pushToCrmCollection.Add(tableName, colcollection);
|
|
// TODO: do we realy need to track each property or just changed ones?
|
|
var props = entry.Entity.GetType().GetProperties();
|
|
if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
|
|
{
|
|
foreach (var elem in props)
|
|
{
|
|
string fieldName = elem.Name;
|
|
|
|
try
|
|
{
|
|
var val = Convert.ToString(elem.GetValue(entry.Entity));
|
|
if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
|
|
{
|
|
_Logger.Log(LogLevel.Debug, "CRM Field Update for " + (entry.Entity is Scenario ? "Scenario" : "Project") + fieldName + "," + val);
|
|
colcollection.Add(fieldName, val);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
if (pushToCrmCollection.Any())
|
|
{
|
|
Guid parentKey = Guid.Empty;
|
|
var entity = entry.Entity as Scenario;
|
|
if (entity != null)
|
|
{
|
|
Scenario s = entity;
|
|
try
|
|
{
|
|
parentKey = Guid.Parse(s.Project.ProjectNumber);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
else if (entry.Entity is Project)
|
|
{
|
|
Project p = (Project)entry.Entity;
|
|
try
|
|
{
|
|
parentKey = Guid.Parse(p.ProjectNumber);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
if (parentKey != Guid.Empty)
|
|
{
|
|
BackgroundProcessManager bpm = new BackgroundProcessManager();
|
|
bpm.UpdateCRMAsync(pushToCrmCollection, parentKey, crmDal, action);
|
|
}
|
|
}
|
|
try
|
|
{
|
|
if (captureForNotification)
|
|
{
|
|
if (entry.Entity is Project)
|
|
{
|
|
if (project.ParentProjectId.HasValue)
|
|
if (changedProjectsDict.ContainsKey(project.ParentProjectId.Value))
|
|
project = changedProjectsDict[project.ParentProjectId.Value];
|
|
string url = Code.Session.AbsoluteUrl.EditProjectUrl(project.Id, this);
|
|
(new NotificationManager(null)).SendProjectChangeNotifications(project, _type, _status, entry.State, url);
|
|
}
|
|
if (entry.Entity is Scenario || entry.Entity is ScenarioDetail)
|
|
{
|
|
if (scenario.Type == (int)ScenarioType.Portfolio)
|
|
{
|
|
string url = Code.Session.AbsoluteUrl.EditScenarioUrl(scenario.Id, this);
|
|
(new NotificationManager(null)).SendScenarioChangeNotifications(scenario, _type, _status, entry.State, url);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception dds)
|
|
{
|
|
_Logger.Error(dds, "error in Capture change notifications!!!");
|
|
}
|
|
}
|
|
}
|
|
|
|
private List<HistorySaveItemPropertyModel> ResolveChanges(ObjectStateEntry stateEntry)
|
|
{
|
|
#region Arguments Validation
|
|
|
|
if (stateEntry == null)
|
|
throw new ArgumentNullException(nameof(stateEntry));
|
|
|
|
#endregion
|
|
|
|
if (stateEntry.State == EntityState.Deleted)
|
|
return new List<HistorySaveItemPropertyModel>();
|
|
|
|
var properties = stateEntry.CurrentValues.DataRecordInfo.FieldMetadata.Select(x => x.FieldType.Name).ToList();
|
|
var changedProperties = new List<HistorySaveItemPropertyModel>(properties.Count);
|
|
|
|
foreach (var propertyName in properties)
|
|
{
|
|
var oldValue = stateEntry.State == EntityState.Added ? DBNull.Value : stateEntry.OriginalValues[propertyName];
|
|
var newValue = stateEntry.CurrentValues[propertyName];
|
|
|
|
// we may not check for null value because if field has null in the database it will be presented as DBNull value here
|
|
if (!oldValue.Equals(newValue))
|
|
{
|
|
changedProperties.Add(new HistorySaveItemPropertyModel
|
|
{
|
|
Name = propertyName,
|
|
OldValue = oldValue.ToString(),
|
|
NewValue = newValue.ToString(),
|
|
});
|
|
}
|
|
}
|
|
|
|
return changedProperties;
|
|
}
|
|
|
|
private string ResolveGroupKey(object entity)
|
|
{
|
|
if (entity == null)
|
|
throw new ArgumentNullException(nameof(entity));
|
|
|
|
if (entity is CostSaving)
|
|
return ((CostSaving)entity).ScenarioId.ToString();
|
|
|
|
if (entity is HolidayAllocation)
|
|
return ((HolidayAllocation)entity).HolidayId.ToString();
|
|
|
|
if (entity is NonProjectTimeResourceAllocation)
|
|
return ((NonProjectTimeResourceAllocation)entity).NonProjectTime2ResourceId.ToString();
|
|
|
|
if (entity is NonProjectTimeTeamAllocation)
|
|
return ((NonProjectTimeTeamAllocation)entity).NonProjectTime2TeamId.ToString();
|
|
|
|
if (entity is PeopleResourceActual)
|
|
return ((PeopleResourceActual)entity).PeopleResourceId.ToString();
|
|
|
|
if (entity is PeopleResourceAllocation)
|
|
return ((PeopleResourceAllocation)entity).ScenarioId.ToString();
|
|
|
|
if (entity is PeopleResourceExpCatChange)
|
|
return ((PeopleResourceExpCatChange)entity).PeopleResourceId.ToString();
|
|
|
|
if (entity is PeopleResource2Team)
|
|
return ((PeopleResource2Team)entity).PeopleResourceId.ToString();
|
|
|
|
if (entity is ScenarioDetail)
|
|
return ((ScenarioDetail)entity).ParentID?.ToString();
|
|
|
|
if (entity is TeamAllocation)
|
|
return ((TeamAllocation)entity).ScenarioId.ToString();
|
|
|
|
if (entity is Security)
|
|
return ((Security)entity).PrincipalId.ToString();
|
|
|
|
if (entity is ProjectAccess)
|
|
return ((ProjectAccess)entity).PrincipalId.ToString();
|
|
|
|
if (entity is Holiday2ExpenditureCategory)
|
|
return ((Holiday2ExpenditureCategory)entity).HolidayId.ToString();
|
|
|
|
if (entity is Holiday2PeopleResource)
|
|
return ((Holiday2PeopleResource)entity).HolidayId.ToString();
|
|
|
|
if (entity is Holiday2Team)
|
|
return ((Holiday2Team)entity).HolidayId.ToString();
|
|
|
|
if (entity is Team2Project)
|
|
return (entity as Team2Project).ProjectId.ToString();
|
|
|
|
if (entity is TagLink)
|
|
return (entity as TagLink).ParentID.ToString();
|
|
|
|
if (entity is StrategicGoal2Project)
|
|
return (entity as StrategicGoal2Project).ProjectId.ToString();
|
|
|
|
return null;
|
|
}
|
|
|
|
private string ResolveEntityId(ObjectStateEntry stateEntryEntity, List<HistorySaveItemPropertyModel> properties)
|
|
{
|
|
if (stateEntryEntity == null)
|
|
throw new ArgumentNullException(nameof(stateEntryEntity));
|
|
|
|
if (stateEntryEntity.EntityKey != null)
|
|
if (stateEntryEntity.EntityKey.EntityKeyValues != null)
|
|
if (stateEntryEntity.EntityKey.EntityKeyValues.Any())
|
|
return stateEntryEntity.EntityKey.EntityKeyValues[0].Value.ToString();
|
|
|
|
if (properties == null || !properties.Any())
|
|
return null;
|
|
|
|
var propertyKey = properties.FirstOrDefault(x => x.Name.ToLower() == "id");
|
|
|
|
return propertyKey?.NewValue;
|
|
}
|
|
|
|
private string ResolveEntityType(ObjectStateEntry stateEntryEntity)
|
|
{
|
|
if (stateEntryEntity == null)
|
|
throw new ArgumentNullException(nameof(stateEntryEntity));
|
|
|
|
if (stateEntryEntity.EntitySet != null)
|
|
{
|
|
if (stateEntryEntity.EntitySet.ElementType != null)
|
|
return stateEntryEntity.EntitySet.ElementType.Name;
|
|
|
|
return stateEntryEntity.EntitySet.Name;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private TransactionInformation TrackChanges()
|
|
{
|
|
#region Refresh Changes
|
|
|
|
// DetectChanges is called as part of the implementation of the SaveChanges.
|
|
// This means that if you override SaveChanges in your context, then DetectChanges will not have been called before your SaveChanges method is called.
|
|
// This can sometimes catch people out, especially when checking if an entity has been modified or not since its state may not be set to Modified until DetectChanges is called.
|
|
// So we need to call it right before we'll try to get changed entities to not skip some changes
|
|
ChangeTracker.DetectChanges();
|
|
|
|
#endregion
|
|
|
|
#region Automatic changes TimeStamping
|
|
|
|
SetTimestamps();
|
|
|
|
#endregion
|
|
|
|
// TODO: AK, review why there is no user
|
|
var executorId = Utils.CurrentUserId();
|
|
var stateManager = ObjectContext().ObjectStateManager;
|
|
var changes = stateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Added | EntityState.Deleted)
|
|
.Where(x => !x.IsRelationship && x.Entity != null &&
|
|
!(x.Entity is History) &&
|
|
!(x.Entity is supt_ImportMessages) &&
|
|
!(x.Entity is supt_tbl_MongoDBBackup) &&
|
|
!(x.Entity is supt_tbl_ProjectIds) &&
|
|
!(x.Entity is supt_tbl_RecParser) &&
|
|
!(x.Entity is FiscalCalendar));
|
|
|
|
var isLocalTransaction = false;
|
|
var transactionId = this.GetClientConnectionId();
|
|
if (transactionId == null)
|
|
{
|
|
transactionId = Guid.NewGuid().ToString();
|
|
isLocalTransaction = true;
|
|
}
|
|
|
|
foreach (var stateEntryEntity in changes)
|
|
{
|
|
if (stateEntryEntity.Entity == null)
|
|
continue;
|
|
|
|
#region Prepare History Items and Log History
|
|
|
|
var groupKey = ResolveGroupKey(stateEntryEntity.Entity);
|
|
var properties = ResolveChanges(stateEntryEntity);
|
|
var entityId = ResolveEntityId(stateEntryEntity, properties);
|
|
var entityType = ResolveEntityType(stateEntryEntity);
|
|
var modificationType = stateEntryEntity.State.ToString();
|
|
|
|
// we do not need to save entity if no properties were changed
|
|
if (stateEntryEntity.State == EntityState.Deleted || properties.Any())
|
|
LogHistory(transactionId, groupKey, entityId, entityType, modificationType, properties);
|
|
|
|
#endregion
|
|
}
|
|
|
|
#region Capture updates for CRM/3rd party systems
|
|
|
|
//capture changes to push to crm
|
|
PushUpdates(changes);
|
|
|
|
#endregion
|
|
|
|
var transactionInfo = new TransactionInformation
|
|
{
|
|
IsLocalTransaction = isLocalTransaction,
|
|
TransactionId = transactionId,
|
|
ExecutorId = executorId
|
|
};
|
|
|
|
return transactionInfo;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |