diff --git a/PARR.AIHITMainSyncer/Services/SyncerService.cs b/PARR.AIHITMainSyncer/Services/SyncerService.cs index 53b3a228..54c10e5b 100644 --- a/PARR.AIHITMainSyncer/Services/SyncerService.cs +++ b/PARR.AIHITMainSyncer/Services/SyncerService.cs @@ -46,16 +46,136 @@ namespace PARR.AIHITMainSyncer.Services private async Task SyncUnitAsync(AihitMainDataMq objFromQuery) { - await SyncFieldsAsync(objFromQuery.Properties); + //Получаем сразу словарь атрибутов, чтобы не ходить каждый раз в базу + var fieldsFromDB = await unitFieldService.Get().AsNoTracking().Select(t => new FieldDto { Id = t.Id, Name = t.AihitName, IsMultipleValue = t.IsMultipleValue }).ToListAsync(); - await SyncValuesAsync(objFromQuery.Properties); + if (!objFromQuery.Properties.Any()) + return; + var listAihitData = new List>(); + + var propertisWithSimpleValues = objFromQuery.Properties + .Where(t => fieldsFromDB.Any(a => IsStringEqual(t.Key, a.Name) && a.IsMultipleValue != true)) + .Select(s => new KeyValuePair(s.Key.Trim(), s.Value?.Trim())).ToList(); + + listAihitData.AddRange(propertisWithSimpleValues); + + var propertiesWithMultipleValues = objFromQuery.Properties.Except(propertisWithSimpleValues).ToList(); + + propertiesWithMultipleValues.ForEach(p => listAihitData.AddRange( + SplitValues(p).Distinct().Select(s => new KeyValuePair(s.Key.Trim(), s.Value?.Trim())) + )); + + var unit = await GetUnit(objFromQuery.Name); + + var unitValuesToRemove = unit.UnitValues.Where(t => !listAihitData.Any(a => + IsStringEqual(t.Field!.AihitName, a.Key) + ) || + !listAihitData.Any(a => + IsStringEqual(t.Field!.AihitName, a.Key) && IsStringEqual(t.Value!.Value, a.Value) + )).ToList(); + unitValuesToRemove.ForEach(uv => unit.UnitValues.Remove(uv)); + + var unitValueExisting = unit.UnitValues.Where(t => listAihitData.Any(a => + IsStringEqual(t.Field!.AihitName, a.Key) && + IsStringEqual(t.Value!.Value, a.Value) + )).ToList(); + + var unitValueMising = listAihitData.Where(t => + !unit.UnitValues.Any(a => + IsStringEqual(t.Key, a.Field!.AihitName) && + IsStringEqual(t.Value, a.Value!.Value) + )).ToList(); + + if (unitValueMising.Any()) + { + var fieldsInChanges = unitValueMising.Select(s => s.Key).Distinct().ToList(); + var valuesInChanges = unitValueMising.Select(s => s.Value).Distinct().ToList(); + + await SyncFieldsAsync(fieldsInChanges!, fieldsFromDB); + + await SyncValuesAsync(valuesInChanges); + + //fieldsInChanges = fieldsInChanges.Select(s => s.ToLower()).ToList()!; + //valuesInChanges = valuesInChanges.Select(s => (s == null) ? null : Sanitize(s.ToLower())).ToList()!; + + var fieldsNameWithId = await unitFieldService.Get().AsNoTracking().Where(t => fieldsInChanges.Any(c => + c == t.AihitName//.AihitName.ToLower() + )).ToListAsync(); + var valuesWithId = await unitFieldValueService.Get().AsNoTracking().Where(t => valuesInChanges.Any(c => + c == t.Value//((t.Value == null) ? null : t.Value.ToLower()) + )).ToListAsync(); + + foreach (var change in unitValueMising) + ApplyChange(unit, fieldsNameWithId, valuesWithId, change); + + if (!await unitService.CommitAsync()) + logger.LogError($"Не удалось применить изменения по актуализиции аттрибуто Unit {unit.Name} в базе данных"); + } + + + //Проверяем наличие всех полей и их значений в справочниках + //var fieldNamesToCreate = objFromQuery.Properties.Keys.Where(t => !fieldsFromDB.Any(a => t == a.Name)); + //foreach (var item in fieldsToCreate) + //{ + + //} + + //Превращаем словарь в лист так как могут содержаться аттрибуты с несколькими значениями + + + + /*var list = new List(); + foreach (var property in objFromQuery.Properties) + { + var key = property.Key; + + var existingField = fieldsFromDB.FirstOrDefault(t => IsStringEqual(t.Name, key)); + + if (existingField == null) + { + var newField = new UnitField { Id = Guid.NewGuid(), AihitName = key, DateCreated = DateTimeOffset.UtcNow }; + + if (await unitFieldService.CreateAsync(newField)) + existingField = new FieldDto { Id = newField.Id, Name = newField.AihitName }; + else { + logger.LogError($"Ошибка создания атрибута с именем {key}"); + return; + } + } + + if(existingField.IsMultipleValue == true) + { + + } else + list.Add(new ValueWithId { FieldId, }) + + + } + /* Unit unit = await GetUnit(objFromQuery.Name); - var changes = GetChangesInUnit(objFromQuery.Properties, unit); + var fieldsFromDB = await unitFieldService.Get().Select(t => new FieldRecord { AihitName = t.AihitName, IsMultipleValue = t.IsMultipleValue }).ToListAsync(); + + var multiValueProperties = GetPropertiesWithMultiValueFields(objFromQuery.Properties, fieldsFromDB); + + var simplifiedProperties = objFromQuery.Properties.Except(multiValueProperties).ToDictionary(t => t.Key, t => t.Value).ToList(); + + var changes = GetChangesInUnit(simplifiedProperties, unit); + + if (multiValueProperties.Any()) + { + var splitedProperties = SplitValue(multiValueProperties); + changes.AddRange(GetChangesInUnit(splitedProperties, unit)); + } if (changes.Any()) { + + await SyncFieldsAsync(changes.Select(s => s.Key).ToList()!, fieldsFromDB); + + await SyncValuesAsync(changes.Select(s => s.Value).ToList()!); + var fieldsNameWithId = await unitFieldService.Get().AsNoTracking().Where(t => changes.Select(c => Sanitize(c.Key.ToLower())).Any(c => c == t.AihitName.ToLower() @@ -66,66 +186,118 @@ namespace PARR.AIHITMainSyncer.Services ((t.Value == null) ? null : t.Value!.ToLower()) )).ToListAsync(); + //Удаляем значения атрибутов, так как это часть индекса и EF не даст просто присвоить значение + var unitValueToRemove = unit.UnitValues.Where(t => fieldsNameWithId.Any(a => a.Id == t.FieldId)); + foreach (var unitValue in unitValueToRemove) + unit.UnitValues.Remove(unitValue); + foreach (var change in changes) { ApplyChange(unit, fieldsNameWithId, valuesWithId, change); } if (!await unitService.CommitAsync()) - logger.LogError($"Не удалось применить изменения по актуализиции аттрибуто Unit {unit.Name} в базе данных"); - } + logger.LogError($"Не удалось применить изменения по актуализиции аттрибуто Unit {unit.Name} в базе данных"); + }*/ + return; } + private static List> SplitValues(Dictionary multiValueProperties) + { + var splitedProperties = new List>(); + foreach (var multiValueProperty in multiValueProperties) + { + if (multiValueProperty.Value == null) + splitedProperties.Add(new KeyValuePair(multiValueProperty.Key, multiValueProperty.Value)); + else + { + var values = multiValueProperty.Value.Split(',').Select(s => s.Trim()); + + foreach (var value in values) + splitedProperties.Add(new KeyValuePair(multiValueProperty.Key, value)); + } + } + + return splitedProperties; + } + + private static List> SplitValues(KeyValuePair multiValueProperty) + { + var splitedProperties = new List>(); + + if (multiValueProperty.Value == null) + splitedProperties.Add(new KeyValuePair(multiValueProperty.Key, multiValueProperty.Value)); + else + { + var values = multiValueProperty.Value.Split(',').Select(s => s.Trim()); + + foreach (var value in values) + splitedProperties.Add(new KeyValuePair(multiValueProperty.Key, value)); + + } + + return splitedProperties; + } private void ApplyChange(Unit unit, List fieldsNameWithId, List valuesWithId, KeyValuePair change) { - var uValue = unit.UnitValues.FirstOrDefault(t => IsStringEqual(t.Field?.AihitName, change.Key)); + // Теперь они все новые + //var uValue = unit.UnitValues.FirstOrDefault(t => IsStringEqual(t.Field?.AihitName, change.Key)); - if (uValue == null) + //if (uValue == null) + //{ + var Field = fieldsNameWithId.FirstOrDefault(t => IsStringEqual(t.AihitName, change.Key)); + var Value = valuesWithId.FirstOrDefault(t => IsStringEqual(t.Value, change.Value)); + + if (Field == null || Value == null) + logger.LogError($"Ошибка присвоения значения({change.Value}) аттрибуту({change.Key}). FieldId - {Field}, ValueId - {Value}"); + else { 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, + FieldId = Field.Id, + ValueId = 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; - } + //} + //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 List> GetChangesInUnit(List> properties, Unit unit) + //{ + // var changes = 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(); + // return changes; + //} - private async Task SyncValuesAsync(Dictionary properties) + private async Task SyncValuesAsync(List values) { // все поля из АИХИТ - var valuesFromAihit = properties.Select(t => t.Value?.Trim()).Distinct(); + var valuesFromAihit = values.Distinct(); // список values для поиска в БД без null - var valuesFromAihitWithoutNull = valuesFromAihit.Where(x => x != null).Select(t => t!.ToLower()).ToList(); + var valuesFromAihitWithoutNull = valuesFromAihit.Where(x => x != null).ToList(); var valuesInDb = await unitFieldValueService.Get().Where(t => (t.Value != null && - valuesFromAihitWithoutNull.Any(x => x == t.Value.ToLower()) + valuesFromAihitWithoutNull.Any(x => x == t.Value) ) || (t.Value == null) ).Select(t => t.Value) @@ -144,7 +316,7 @@ namespace PARR.AIHITMainSyncer.Services { Id = Guid.NewGuid(), DateCreated = DateTimeOffset.UtcNow, - Value = Sanitize(item) + Value = item }; if (!await unitFieldValueService.CreateAsync(value)) @@ -158,10 +330,10 @@ namespace PARR.AIHITMainSyncer.Services } - private async Task SyncFieldsAsync(Dictionary properties) + private async Task SyncFieldsAsync(List fieldsFromAihit, List fieldsFromDB) { - var fields = properties.Select(t => t.Key.Trim()); - var newFields = fields.Where(t => !unitFieldService.Get().Any(f => f.AihitName.ToLower() == t.ToLower())); + var newFields = fieldsFromAihit.Where(t => !fieldsFromDB.Any(f => f.Name == t)); + if (newFields.Any()) { foreach (var item in newFields) @@ -169,7 +341,7 @@ namespace PARR.AIHITMainSyncer.Services var field = new UnitField { Id = Guid.NewGuid(), - AihitName = Sanitize(item)!, + AihitName = item, EsppName = null, }; @@ -184,17 +356,36 @@ namespace PARR.AIHITMainSyncer.Services } - private string? Sanitize(string? value) - { - var _value = value?.Trim(); - return _value; - } + //private Dictionary GetPropertiesWithMultiValueFields(Dictionary properties, List fieldsFromDB) + //{ + // var fieldsName = properties.Select(s => Sanitize(s.Key.ToLower())); + + // //var multiValueField = await unitFieldService.Get().Where(t => + // // t.IsMultipleValue == true && + // // fieldsName.Any(p => p == t.AihitName.ToLower()) + // // ).Select(s => s.AihitName.ToLower()).ToListAsync(); + + // var multiValueField = fieldsFromDB.Where(t => t.IsMultipleValue == true + // && fieldsName.Any(p => p == t.AihitName.ToLower())) + // .Select(s => s.AihitName.ToLower()).ToList(); + + // return properties.Where(p => multiValueField.Any(a => Sanitize(p.Key.ToLower()) == a)).ToDictionary(t => t.Key, t => t.Value); + //} + + + //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(); + //var _value1 = value1?.ToLower().Trim(); + //var _value2 = value2?.ToLower().Trim(); + var _value1 = value1; + var _value2 = value2; return _value1 == _value2; } @@ -238,4 +429,33 @@ namespace PARR.AIHITMainSyncer.Services .ThenInclude(uf => uf.Value); } } + + //internal record FieldRecord + //{ + // public required string AihitName; + + // public bool? IsMultipleValue; + + //} + + //internal class ValueWithId + //{ + // public required Guid FieldId; + + // public required string FieldName; + + // public required Guid ValueId; + + // public required string? ValueValue; + + //} + + internal record FieldDto + { + public required Guid Id; + + public required string Name; + + public bool? IsMultipleValue; + } } \ No newline at end of file diff --git a/PARR.AIHITSyncerWorker/appsettings.Development.json b/PARR.AIHITSyncerWorker/appsettings.Development.json index b2dcdb67..3b67da3f 100644 --- a/PARR.AIHITSyncerWorker/appsettings.Development.json +++ b/PARR.AIHITSyncerWorker/appsettings.Development.json @@ -1,8 +1,11 @@ { - "Logging": { - "LogLevel": { + "Serilog": { + "MinimumLevel": { "Default": "Information", - "Microsoft.Hosting.Lifetime": "Information" + "Override": { + //"Microsoft": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } } } -} +} \ No newline at end of file