feat(aihitMainSyncer): Переписан под возможность обработки нескольких значений для одного атрибута.

This commit is contained in:
Mikhail Kuznetsov
2025-09-25 13:54:33 +10:00
parent 6cc6dac4f7
commit a3ed9d0103
2 changed files with 269 additions and 46 deletions

View File

@@ -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<KeyValuePair<string, string?>>();
var propertisWithSimpleValues = objFromQuery.Properties
.Where(t => fieldsFromDB.Any(a => IsStringEqual(t.Key, a.Name) && a.IsMultipleValue != true))
.Select(s => new KeyValuePair<string, string?>(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<string, string?>(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<ValueWithId>();
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<KeyValuePair<string, string?>> SplitValues(Dictionary<string, string?> multiValueProperties)
{
var splitedProperties = new List<KeyValuePair<string, string?>>();
foreach (var multiValueProperty in multiValueProperties)
{
if (multiValueProperty.Value == null)
splitedProperties.Add(new KeyValuePair<string, string?>(multiValueProperty.Key, multiValueProperty.Value));
else
{
var values = multiValueProperty.Value.Split(',').Select(s => s.Trim());
foreach (var value in values)
splitedProperties.Add(new KeyValuePair<string, string?>(multiValueProperty.Key, value));
}
}
return splitedProperties;
}
private static List<KeyValuePair<string, string?>> SplitValues(KeyValuePair<string, string?> multiValueProperty)
{
var splitedProperties = new List<KeyValuePair<string, string?>>();
if (multiValueProperty.Value == null)
splitedProperties.Add(new KeyValuePair<string, string?>(multiValueProperty.Key, multiValueProperty.Value));
else
{
var values = multiValueProperty.Value.Split(',').Select(s => s.Trim());
foreach (var value in values)
splitedProperties.Add(new KeyValuePair<string, string?>(multiValueProperty.Key, value));
}
return splitedProperties;
}
private void ApplyChange(Unit unit, List<UnitField> fieldsNameWithId, List<UnitFieldValue> valuesWithId, KeyValuePair<string, string?> 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<KeyValuePair<string, string?>> GetChangesInUnit(Dictionary<string, string?> 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<KeyValuePair<string, string?>> GetChangesInUnit(List<KeyValuePair<string, string?>> 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<string, string?> properties)
private async Task SyncValuesAsync(List<string?> 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<string, string?> properties)
private async Task SyncFieldsAsync(List<string> fieldsFromAihit, List<FieldDto> 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<string, string?> GetPropertiesWithMultiValueFields(Dictionary<string, string?> properties, List<FieldRecord> 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;
}
}