Files
parr_api/PARR.AIHITMainSyncer/Services/SyncerService.cs

461 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
using PARR.DAL.Models.Unit;
using PARR.DAL.Services.Interfaces.Unit;
namespace PARR.AIHITMainSyncer.Services
{
internal class SyncerService : ISyncerService
{
private readonly ILogger<SyncerService> logger;
private readonly ITransformService transformService;
private readonly IUnitService unitService;
private readonly IUnitFieldService unitFieldService;
private readonly IUnitFieldValueService unitFieldValueService;
public SyncerService(
ILogger<SyncerService> logger,
ITransformService transformService,
IUnitService unitService,
IUnitFieldService unitFieldService,
IUnitFieldValueService unitFieldValueService
)
{
this.logger = logger;
this.transformService = transformService;
this.unitService = unitService;
this.unitFieldService = unitFieldService;
this.unitFieldValueService = unitFieldValueService;
}
public async Task SyncAsync(string msg)
{
//logger.LogInformation("Запуск синхронизации данных из очереди сообщений в ПАРР.");
var objFromQuery = transformService.GetModelFromJson<AihitMainDataMq>(msg);
if (objFromQuery == null)
return;
await SyncUnitAsync(objFromQuery);
}
private async Task SyncUnitAsync(AihitMainDataMq objFromQuery)
{
//Получаем сразу словарь атрибутов, чтобы не ходить каждый раз в базу
var fieldsFromDB = await unitFieldService.Get().AsNoTracking().Select(t => new FieldDto { Id = t.Id, Name = t.AihitName, IsMultipleValue = t.IsMultipleValue }).ToListAsync();
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 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()
)).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();
//Удаляем значения атрибутов, так как это часть индекса и 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} в базе данных");
}*/
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));
//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 = 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;
//}
}
//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(List<string?> values)
{
// все поля из АИХИТ
var valuesFromAihit = values.Distinct();
// список values для поиска в БД без null
var valuesFromAihitWithoutNull = valuesFromAihit.Where(x => x != null).ToList();
var valuesInDb = await unitFieldValueService.Get().Where(t =>
(t.Value != null &&
valuesFromAihitWithoutNull.Any(x => x == t.Value)
)
|| (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 = 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(List<string> fieldsFromAihit, List<FieldDto> fieldsFromDB)
{
var newFields = fieldsFromAihit.Where(t => !fieldsFromDB.Any(f => f.Name == t));
if (newFields.Any())
{
foreach (var item in newFields)
{
var field = new UnitField
{
Id = Guid.NewGuid(),
AihitName = 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 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;
var _value2 = value2;
return _value1 == _value2;
}
private async Task<Unit> GetUnit(string name)
{
var unit = await GetUnitByName(name.Trim());
if (unit == null)
unit = await CreateUnitAsync(name);
return unit;
}
private async Task<Unit> 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 unit;
}
public async Task<Unit?> GetUnitByName(string name)
{
return await GetUnitWithFieldsAndValues()
.FirstOrDefaultAsync(u => u.Name.ToLower() == name.ToLower());
}
private IQueryable<Unit> GetUnitWithFieldsAndValues()
{
return unitService.Get()
.Include(t => t.UnitValues)
.ThenInclude(uv => uv.Field)
.Include(t => t.UnitValues)
.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;
}
}