282 lines
12 KiB
C#
282 lines
12 KiB
C#
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.Trim(), a.Name) && a.IsMultipleValue != true))
|
||
.Where(t => fieldsFromDB.Any(a => IsStringEqual(t.Key.Trim(), a.AihitName) && a.IsMultipleValue != true))
|
||
.Select(s => new KeyValuePair<string, string?>(s.Key.Trim(), s.Value?.Trim())).ToList();
|
||
|
||
listAihitData.AddRange(propertisWithSimpleValues);
|
||
|
||
var propertiesWithMultipleValues = objFromQuery.Properties.Where(t => !propertisWithSimpleValues.Any(a => t.Key.Trim() == a.Key)).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} в базе данных");
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
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 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);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
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)
|
||
private async Task SyncFieldsAsync(List<string> fieldsFromAihit, List<UnitField> fieldsFromDB)
|
||
{
|
||
//var newFields = fieldsFromAihit.Where(t => !fieldsFromDB.Any(f => f.Name == t));
|
||
var newFields = fieldsFromAihit.Where(t => !fieldsFromDB.Any(f => f.AihitName == 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}", item, field);
|
||
else
|
||
logger.LogInformation("Создана запись а таблице Fields: Fields:{item},{field}", item, field);
|
||
}
|
||
if (!await unitFieldService.CommitAsync())
|
||
logger.LogError($"Не удалось применить изменения по добавлению новых Fields в базе данных");
|
||
}
|
||
}
|
||
|
||
|
||
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);
|
||
}
|
||
}
|
||
} |