diff --git a/PARR.AIHITMainLoader/Models/PtkData.cs b/PARR.AIHITMainLoader/Models/PtkData.cs index b3223da8..585ef376 100644 --- a/PARR.AIHITMainLoader/Models/PtkData.cs +++ b/PARR.AIHITMainLoader/Models/PtkData.cs @@ -8,140 +8,140 @@ namespace PARR.AIHITMainLoader.Models { [Column("IP_АДРЕС")] public string? IP { get; set; } - + [Column("МЕТКА")] public string? Metka { get; set; } - + [Column("АКТИВЕН")] public string? IsActive { get; set; } - + [Column("ВАЖНЫЙ_ЭК")] public string? IsImportant { get; set; } - + [Column("ВРЕМЯ_СОЗДАНИЯ")] public DateTime? CreateTime { get; set; } - + [Column("ДОПОЛНИТЕЛЬНАЯ_ИНФОРМАЦИЯ")] public string? AdditionalInfo { get; set; } - + [Column("ЗОНА_ОТВЕТСТВЕННОСТИ")] public string? ResponseArea { get; set; } - + [Column("КАТЕГОРИЯ_ЭК")] public string? EKCategory { get; set; } - + [Column("КОД_ПОИСКА_ЭК")] public string? EKFindCode { get; set; } - + [Column("КОД_ПРОДУКТА")] public string? ProductCode { get; set; } - + [Column("КОД_УСЛУГИ")] public string? ServiceCode { get; set; } - + [Column("КРАТКОЕ_НАИМЕНОВАНИЕ")] public string? ShortName { get; set; } - + [Column("ОТВЕТСТВЕННЫЙ_ЗА_ЭК")] public string? ResponsibleByEK { get; set; } - + [Column("ПЛАНОВОЕ_ВРЕМЯ_ВОССТАНОВЛЕНИЯ")] public DateTime? PlannedTimeToRepair { get; set; } - + [Column("ПОДКАТЕГОРИЯ_ЭК")] public string? EKSubCategory { get; set; } - + [Column("ПОЛНОЕ_НАИМЕНОВАНИЕ")] public string? FullName { get; set; } - + [Column("ПРЕДПИСАНИЕ")] public string? Prescription { get; set; } - + [Column("ПРЕДПРИЯТИЕ")] public string? Company { get; set; } - + [Column("РАБОЧАЯ_ГР_ОТВ_ЗА_ЭК")] public string? WorkGroup { get; set; } - + [Column("РАСПОЛОЖЕНИЕ")] public string? Location { get; set; } - + [Column("РЕВИЗОР_ЭК")] public string? EKRevizor { get; set; } - + [Column("РЕГИСТРАТОР_ЭК")] public string? EKRegister { get; set; } - + [Column("СЕТЕВОЕ_ИМЯ")] public string? NetworkName { get; set; } - + [Column("СТАТУС")] public string? Status { get; set; } - + [Column("ТИП_ЭК")] public string? EKType { get; set; } - + [Column("ФАКТИЧЕСКОЕ_ЗАВЕРШЕНИЕ_ЭКСПЛУАТАЦИИ")] public DateTime? EndExplotationDate { get; set; } - + [Column("ФАКТИЧЕСКОЕ_НАЧАЛО_ЭКСПЛУАТАЦИИ")] public DateTime? StartExplotationDate { get; set; } - + [Column("ЦЕЛЕВОЕ_ВРЕМЯ_ВОССТАНОВЛЕНИЯ")] public string? TargetRepairTime { get; set; } - + [Column("SYSMODTIME")] public DateTime? SysModTime { get; set; } - + [Column("SYSMODUSER")] public string? SysModUser { get; set; } - + [Column("НОВЫЙ_КОД_ПОИСКА")] public string? NewEKFindCode { get; set; } - + [Column("СТАРЫЙ_КОД_ПОИСКА")] public string? OldEKFindCode { get; set; } - + [Column("НАПРАВЛЕНИЕ_ЦТС_ЦК")] public string? CTSDirection { get; set; } - + [Key] [Column("ID")] public int? AIHID { get; set; } - + [Column("недостоверные_данные")] public char? IsUnreliableData { get; set; } - + [Column("РГ_смены")] public string? ShiftWorkGroup { get; set; } - + [Column("Клиентское_ПО")] public string? ClientSoftware { get; set; } - + [Column("Клиентская_ОС")] public string? ClientOS { get; set; } - + [Column("Тип СУБД")] public string? DBType { get; set; } - + [Column("Тип сервера приложений")] public string? APPType { get; set; } - + [Column("Тип сервера ЦК БС")] public string? CKBSServerType { get; set; } - + [Column("Тип сервера ИБ")] public string? IBServerType { get; set; } - + [Column("Тип сервера инфраструктуры")] public string? InfrastructureServerType { get; set; } - + [Column("Тип сервера мониторинга")] public string? MonitoringServerType { get; set; } - + [Column("ОС")] public string? OSType { get; set; } - + [Column("ЗО_РГ")] public string? WorkGroupResponseArea { get; set; } @@ -154,39 +154,39 @@ namespace PARR.AIHITMainLoader.Models Properties = new Dictionary { {"IP_АДРЕС", IP }, - {"МЕТКА", Metka }, - {"АКТИВЕН", IsActive }, - {"ВАЖНЫЙ_ЭК", IsImportant }, - {"ВРЕМЯ_СОЗДАНИЯ", CreateTime.ToString() ?? null}, - {"ДОПОЛНИТЕЛЬНАЯ_ИНФОРМАЦИЯ", AdditionalInfo }, + //{"МЕТКА", Metka }, + //{"АКТИВЕН", IsActive }, + //{"ВАЖНЫЙ_ЭК", IsImportant }, + //{"ВРЕМЯ_СОЗДАНИЯ", CreateTime.ToString() ?? null}, + //{"ДОПОЛНИТЕЛЬНАЯ_ИНФОРМАЦИЯ", AdditionalInfo }, {"КАТЕГОРИЯ_ЭК", EKCategory }, - {"КОД_ПРОДУКТА", EKFindCode }, - {"КОД_УСЛУГИ", ProductCode }, + //{"КОД_ПРОДУКТА", EKFindCode }, + //{"КОД_УСЛУГИ", ProductCode }, {"КРАТКОЕ_НАИМЕНОВАНИЕ", ShortName }, {"ОТВЕТСТВЕННЫЙ_ЗА_ЭК", ResponsibleByEK }, - {"ПЛАНОВОЕ_ВРЕМЯ_ВОССТАНОВЛЕНИЯ", PlannedTimeToRepair.ToString() ?? null }, + //{"ПЛАНОВОЕ_ВРЕМЯ_ВОССТАНОВЛЕНИЯ", PlannedTimeToRepair.ToString() ?? null }, {"ПОДКАТЕГОРИЯ_ЭК", EKSubCategory }, {"ПОЛНОЕ_НАИМЕНОВАНИЕ", FullName }, - {"ПРЕДПИСАНИЕ", Prescription }, - {"ПРЕДПРИЯТИЕ", Company }, + //{"ПРЕДПИСАНИЕ", Prescription }, + //{"ПРЕДПРИЯТИЕ", Company }, {"РАБОЧАЯ_ГР_ОТВ_ЗА_ЭК", WorkGroup }, - {"РАСПОЛОЖЕНИЕ", Location }, - {"РЕВИЗОР_ЭК", EKRevizor }, - {"РЕГИСТРАТОР_ЭК", EKRegister }, - {"СЕТЕВОЕ_ИМЯ", NetworkName }, + //{"РАСПОЛОЖЕНИЕ", Location }, + //{"РЕВИЗОР_ЭК", EKRevizor }, + //{"РЕГИСТРАТОР_ЭК", EKRegister }, + //{"СЕТЕВОЕ_ИМЯ", NetworkName }, {"СТАТУС", Status }, {"ТИП_ЭК", EKType }, - {"ФАКТИЧЕСКОЕ_ЗАВЕРШЕНИЕ_ЭКСПЛУАТАЦИИ", EndExplotationDate.ToString() ?? null }, - {"ФАКТИЧЕСКОЕ_НАЧАЛО_ЭКСПЛУАТАЦИИ", StartExplotationDate.ToString() ?? null }, - {"ЦЕЛЕВОЕ_ВРЕМЯ_ВОССТАНОВЛЕНИЯ", TargetRepairTime }, - {"SYSMODTIME", SysModTime.ToString() ?? null }, - {"SYSMODUSER", SysModUser }, - {"НОВЫЙ_КОД_ПОИСКА", NewEKFindCode }, - {"СТАРЫЙ_КОД_ПОИСКА", OldEKFindCode }, - {"НАПРАВЛЕНИЕ_ЦТС_ЦК", CTSDirection }, - {"ID", AIHID.ToString() }, - {"недостоверные_данные", IsUnreliableData.ToString() }, - {"РГ_смены", ShiftWorkGroup }, + //{"ФАКТИЧЕСКОЕ_ЗАВЕРШЕНИЕ_ЭКСПЛУАТАЦИИ", EndExplotationDate.ToString() ?? null }, + //{"ФАКТИЧЕСКОЕ_НАЧАЛО_ЭКСПЛУАТАЦИИ", StartExplotationDate.ToString() ?? null }, + //{"ЦЕЛЕВОЕ_ВРЕМЯ_ВОССТАНОВЛЕНИЯ", TargetRepairTime }, + //{"SYSMODTIME", SysModTime.ToString() ?? null }, + //{"SYSMODUSER", SysModUser }, + //{"НОВЫЙ_КОД_ПОИСКА", NewEKFindCode }, + //{"СТАРЫЙ_КОД_ПОИСКА", OldEKFindCode }, + //{"НАПРАВЛЕНИЕ_ЦТС_ЦК", CTSDirection }, + //{"ID", AIHID.ToString() }, + //{"недостоверные_данные", IsUnreliableData.ToString() }, + //{"РГ_смены", ShiftWorkGroup }, {"Клиентское_ПО", ClientSoftware }, {"Клиентская_ОС", ClientOS }, {"Тип СУБД", DBType }, diff --git a/PARR.AIHITMainSyncer/Services/SyncerService.cs b/PARR.AIHITMainSyncer/Services/SyncerService.cs index 2b25fc07..2acb0e1d 100644 --- a/PARR.AIHITMainSyncer/Services/SyncerService.cs +++ b/PARR.AIHITMainSyncer/Services/SyncerService.cs @@ -1,4 +1,6 @@ -using Microsoft.Extensions.Logging; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; using PARR.BLL.Domain.Mq; using PARR.BLL.Services.Interfaces; using PARR.DAL.Extensions; @@ -44,174 +46,196 @@ namespace PARR.AIHITMainSyncer.Services private async Task SyncUnitAsync(AihitMainDataMq objFromQuery) { - var isChanged = false; + await SyncFieldsAsync(objFromQuery.Properties); - var unit = await unitService.GetUnitByName(objFromQuery.Name); + await SyncValuesAsync(objFromQuery.Properties); - foreach (var item in objFromQuery.Properties) - { //актуализируем справочники в соответствии с пришедшими данными - var field = await CreateUnitFieldIfNotExistAsync(item.Key); - var value = await CreateFieldValueIfNotExistAsync(field, item.Value); + Unit unit = await GetUnit(objFromQuery.Name); - //Если ЭК не найден то создаём его - if (unit == null) - unit = await CreateUnitAsync(objFromQuery); - //else - // logger.LogDebug($"Найден Unit в БД: {unit.Name})"); + var changes = GetChangesInUnit(objFromQuery.Properties, unit); - //теперь проверяем наличие поля связанного с этим ЭК - if (SyncFields(unit, field) && !isChanged) - isChanged = true; - - //Синхронизируем значение - if (SyncValues(unit, field, value) && !isChanged) - isChanged = true; - } - - if (isChanged && !await unitService.CommitAsync()) - logger.LogError($"Не удалось изменить Unit {objFromQuery.Name}"); - else - logger.LogInformation($"----- Набор данных в Unit изменён: {objFromQuery.Name} -----"); - } - - - private bool SyncFields(Unit unit, UnitField field) - { - var isChanged = false; - - var fieldInUnit = unit!.UnitFields.FirstOrDefault(u => u.FieldId == field.Id); - - if (fieldInUnit == null) + if (changes.Any()) { - if (!isChanged) isChanged = true; - unit.UnitFields.Add( - new UnitInField { UnitId = unit.Id, FieldId = field.Id, DateCreated = DateTimeOffset.UtcNow } - ); - } + var fieldsNameWithId = await unitFieldService.Get().AsNoTracking().Where(t => changes.Select(c => + Sanitize(c.Key.ToLower())).Any(c => + c == t.AihitName.ToLower() + )).ToListAsync(); + var valuesWithId = await unitFieldValueService.Get().AsNoTracking().Where(t => changes.Select(c => + (c.Value == null) ? null : Sanitize(c.Value.ToLower()) + ).Any(c => c == + ((t.Value == null) ? null : t.Value!.ToLower()) + )).ToListAsync(); - return isChanged; - } - - - private bool SyncValues(Unit unit, UnitField field, UnitFieldValue value) - { - var isChanged = false; - - var valueInUnit = unit!.UnitValues.FirstOrDefault(uv => uv.FieldId == field.Id); - - if (valueInUnit == null) - { - if (!isChanged) isChanged = true; - unit.UnitValues.Add( - new UnitInValue - { - UnitId = unit.Id, - FieldId = field.Id, - ValueId = value.Id, - DateCreated = DateTime.UtcNow - } - ); - } - else if (valueInUnit.Value != value) - { - if (!isChanged) isChanged = true; + foreach (var change in changes) { - valueInUnit.ValueId = value.Id; - valueInUnit.DateModified = DateTime.UtcNow; + ApplyChange(unit, fieldsNameWithId, valuesWithId, change); } - } - return isChanged; + if (!await unitService.CommitAsync()) + logger.LogError($"Не удалось применить изменения по актуализиции аттрибуто Unit {unit.Name} в базе данных"); + } } - private async Task CreateUnitAsync(AihitMainDataMq objFromQuery) + private void ApplyChange(Unit unit, List fieldsNameWithId, List valuesWithId, KeyValuePair change) { - var unit = new Unit { Name = objFromQuery.Name.Trim() }; + var uValue = unit.UnitValues.FirstOrDefault(t => IsStringEqual(t.Field?.AihitName, change.Key)); + + if (uValue == null) + { + var f = new UnitInValue + { + UnitId = unit.Id, + FieldId = fieldsNameWithId.First(t => IsStringEqual(t.AihitName, change.Key)).Id, + ValueId = valuesWithId.First(t => IsStringEqual(t.Value, change.Value)).Id, + DateCreated = DateTimeOffset.UtcNow + }; + + unit.UnitValues.Add(f); + } + else + { + uValue.ValueId = valuesWithId.First(t => IsStringEqual(t.Value, change.Value)).Id; + uValue.DateModified = DateTimeOffset.UtcNow; + } + } + + + private List> GetChangesInUnit(Dictionary properties, Unit unit) + { + return properties.Where(t => + !unit.UnitValues.Any( + uv => uv.Field!.AihitName.ToLower() == Sanitize(t.Key.ToLower()) && ( + (t.Value == null) ? + uv.Value?.Value == null : + ((uv.Value?.Value == null) ? null : uv.Value!.Value!.ToLower()) == Sanitize(t.Value.ToLower()) + ) + ) + ).ToList(); + } + + + private async Task SyncValuesAsync(Dictionary properties) + { + // все поля из АИХИТ + var valuesFromAihit = properties.Select(t => t.Value?.Trim()).Distinct(); + + // список values для поиска в БД без null + var valuesFromAihitWithoutNull = valuesFromAihit.Where(x => x != null).Select(t => t!.ToLower()).ToList(); + + var valuesInDb = await unitFieldValueService.Get().Where(t => + (t.Value != null && + valuesFromAihitWithoutNull.Any(x => x == t.Value.ToLower()) + ) + || (t.Value == null) + ).Select(t => t.Value) + .ToListAsync(); + + if (!valuesFromAihit.Any(x => x == null)) + valuesInDb.Remove(null); + + var newValues = valuesFromAihit.Where(t => !valuesInDb.Any(x => IsStringEqual(x, t))).ToList(); + + if (newValues.Any()) + { + foreach (var item in newValues) + { + var value = new UnitFieldValue + { + Id = Guid.NewGuid(), + DateCreated = DateTimeOffset.UtcNow, + Value = Sanitize(item) + }; + + if (!await unitFieldValueService.CreateAsync(value)) + logger.LogError($"Не удалось создать запись в таблице FieldValues: {item}, {value.ToJson()}"); + else + logger.LogInformation($"Создана запись а таблице FieldValues: {item}, {value.ToJson()}"); + } + if (!await unitFieldValueService.CommitAsync()) + logger.LogError($"Не удалось применить изменения по добавлению новых Fields в базе данных"); + } + } + + + private async Task SyncFieldsAsync(Dictionary properties) + { + var fields = properties.Select(t => t.Key.Trim()); + var newFields = fields.Where(t => !unitFieldService.Get().Any(f => f.AihitName.ToLower() == t.ToLower())); + if (newFields.Any()) + { + foreach (var item in newFields) + { + var field = new UnitField + { + Id = Guid.NewGuid(), + AihitName = Sanitize(item)!, + EsppName = null, + }; + + if (!await unitFieldService.CreateAsync(field)) + logger.LogError($"Не удалось создать запись в таблице Fields: {item}, {field.ToJson()}"); + else + logger.LogInformation($"Создана запись а таблице Fields: {item}, {field.ToJson()}"); + } + if (!await unitFieldService.CommitAsync()) + logger.LogError($"Не удалось применить изменения по добавлению новых Fields в базе данных"); + } + } + + + private string? Sanitize(string? value) + { + var _value = value?.Trim(); + return _value; + } + + + private bool IsStringEqual(string? value1, string? value2) + { + var _value1 = value1?.ToLower().Trim(); + var _value2 = value2?.ToLower().Trim(); + return _value1 == _value2; + } + + + private async Task GetUnit(string name) + { + var unit = await GetUnitByName(name.Trim()); + + if (unit == null) + unit = await CreateUnitAsync(name); + + return unit; + } + + private async Task CreateUnitAsync(string name) + { + var unit = new Unit { Name = name.Trim() }; if (!await unitService.CreateAsync(unit) || !await unitService.CommitAsync()) logger.LogError($"Не удалось создать Unit {unit.Name}"); else logger.LogInformation($"----- Создан Unit: {unit.Name} -----"); - return (await unitService.GetUnitByName(unit.Name))!; + return unit; } - private async Task CreateUnitFieldIfNotExistAsync(string name) + public async Task GetUnitByName(string name) { - var existUnitField = await unitFieldService.GetByAihitNameAsync(name); - - if (existUnitField != null) - return existUnitField; - - var field = new UnitField - { - Id = Guid.NewGuid(), - AihitName = name.Trim(), - EsppName = null, - }; - - if (!await unitFieldService.CreateAsync(field) || !await unitFieldService.CommitAsync()) - logger.LogError($"Не удалось создать запись в таблице Fields: {name}, {field.ToJson()}"); - else - logger.LogInformation($"Создана запись а таблице Fields: {name}, {field.ToJson()}"); - - return (await unitFieldService.GetAsync(field.Id))!; + return await GetUnitWithFieldsAndValues() + .FirstOrDefaultAsync(u => u.Name.ToLower() == name.ToLower()); } - private async Task CreateFieldValueIfNotExistAsync(UnitField field, string? value) + private IQueryable GetUnitWithFieldsAndValues() { - var existUnitFieldValue = await unitFieldValueService.GetByValueNameAsync(value); - - //если значение существует отдаем его - if (existUnitFieldValue != null) - { - //проверяем связь с таблицей Fields - if (existUnitFieldValue.FieldValues.FirstOrDefault(fv => fv.FieldId == field.Id) == null) - { - var unitFieldInUnitFieldValue = new UnitFieldInUnitFieldValue - { - FieldId = field.Id, - FieldValueId = existUnitFieldValue.Id, - DateCreated = DateTime.UtcNow, - }; - - existUnitFieldValue.FieldValues.Add(unitFieldInUnitFieldValue); - - if (!await unitFieldValueService.CommitAsync()) - logger.LogError($"Не удалось создать связь таблицы FieldValues и Fields: {unitFieldValueService.ToJson()}"); - else - logger.LogInformation($"Создана связь таблицы FieldValues и Fields: {unitFieldValueService.ToJson()}"); - } - - return existUnitFieldValue; - } - - //значение не найдено значит создаём его - var newValue = new UnitFieldValue - { - Id = Guid.NewGuid(), - Value = (value == null) ? null : value.Trim() - }; - //и привязываем значение к полю - newValue.FieldValues.Add( - new UnitFieldInUnitFieldValue - { - FieldId = field.Id, - FieldValueId = newValue.Id, - DateCreated = DateTime.UtcNow, - } - ); - - //пишем в базу данных - if (!await unitFieldValueService.CreateAsync(newValue) || !await unitFieldValueService.CommitAsync()) - logger.LogError($"Не удалось создать запись в таблице Values: {newValue.Value}, {newValue.ToJson()}"); - else - logger.LogInformation($"Создана запись а таблице Values: {newValue.Value}, {newValue.ToJson()}"); - - return (await unitFieldValueService.GetAsync(newValue.Id))!; + return unitService.Get() + .Include(t => t.UnitValues) + .ThenInclude(uv => uv.Field) + .Include(t => t.UnitValues) + .ThenInclude(uf => uf.Value); } } -} +} \ No newline at end of file diff --git a/PARR.DAL/Services/Implementations/Unit/UnitService.cs b/PARR.DAL/Services/Implementations/Unit/UnitService.cs index a7814aae..6697d539 100644 --- a/PARR.DAL/Services/Implementations/Unit/UnitService.cs +++ b/PARR.DAL/Services/Implementations/Unit/UnitService.cs @@ -18,22 +18,5 @@ namespace PARR.DAL.Services.Implementations.Unit { this.dataContext = dataContext; } - - - public async Task GetUnitByName(string name) - { - return await GetUnitWithFieldsAndValues() - .FirstOrDefaultAsync(u => u.Name.ToLower() == name.ToLower()); - } - - - private IQueryable GetUnitWithFieldsAndValues() - { - return EntitySet - .Include(u => u.UnitFields) - .ThenInclude(f => f.UnitField) - .Include(u => u.UnitValues) - .ThenInclude(v => v.Value); - } } } diff --git a/PARR.DAL/Services/Interfaces/Unit/IUnitService.cs b/PARR.DAL/Services/Interfaces/Unit/IUnitService.cs index 3a5bebc1..534cc21c 100644 --- a/PARR.DAL/Services/Interfaces/Unit/IUnitService.cs +++ b/PARR.DAL/Services/Interfaces/Unit/IUnitService.cs @@ -4,6 +4,5 @@ namespace PARR.DAL.Services.Interfaces.Unit { public interface IUnitService : IBaseService { - Task GetUnitByName(string name); } }