216 lines
9.1 KiB
C#
216 lines
9.1 KiB
C#
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.Logging;
|
||
using PARR.AIHITRelationshipsSyncer.Models;
|
||
using PARR.AIHITRelationshipsSyncer.Services.Interfaces;
|
||
using PARR.AIHITRelationshipsSyncer.Settings;
|
||
using PARR.DAL.Models.Unit;
|
||
using PARR.DAL.Services.Interfaces.Unit;
|
||
using System.Reactive;
|
||
using Unit = PARR.DAL.Models.Unit.Unit;
|
||
|
||
namespace PARR.AIHITRelationshipsSyncer.Services.Implementations
|
||
{
|
||
internal class RelationshipsSyncSrevice : IRelationshipsSyncService
|
||
{
|
||
private readonly ILogger<RelationshipsSyncSrevice> logger;
|
||
private readonly IUnitService unitService;
|
||
private readonly WorkerSettings workerSettings;
|
||
|
||
public RelationshipsSyncSrevice(ILogger<RelationshipsSyncSrevice> logger,
|
||
IUnitService unitService,
|
||
WorkerSettings workerSettings
|
||
)
|
||
{
|
||
this.logger = logger;
|
||
this.unitService = unitService;
|
||
this.workerSettings = workerSettings;
|
||
}
|
||
|
||
|
||
public async Task SyncAsync(List<AihitData> aihitdata)
|
||
{
|
||
var groupedData = aihitdata.Where(t => t.EKFindCode != null && t.ChildEk != null).GroupBy(ad => ad.EKFindCode);
|
||
//var i = 0;
|
||
//var c = groupedData.Count();
|
||
|
||
var onlyUpdateTransactionCount = 0;
|
||
//Перебираем сгруппированные по родительскому ЭК данные
|
||
foreach (var parrent in groupedData)
|
||
{
|
||
//i = i+1;
|
||
|
||
//Получаем имя родителя
|
||
var parentName = parrent.First().EKFindCode;
|
||
|
||
//По имени получаем экземпляр Unit со всеми дочерними связями
|
||
var unit = await GetUnitByNameAsync(parentName!);
|
||
|
||
if (unit == null)
|
||
{
|
||
logger.LogError($"Не удалось получиться родительский ЭК по имени{parentName}");
|
||
return;
|
||
}
|
||
|
||
//Из данных АИХ ИТ получаем имена всех дочерних ЭК
|
||
var childsName = parrent.Where(t => t.ChildEk != parentName && t.ChildEk != null).Select(t => t.ChildEk);
|
||
|
||
//Убираем ЭК типа РПА-РОБИН-РЦКУ-СПИУИ-ИНФО-27-ГОР и РПА - РОБИН - РЦКУ - СПиУИ - ИНФО - 27 - ГОР
|
||
childsName = childsName.Select(t => t?.ToLower().Trim()).Distinct();
|
||
|
||
//Проходим циклом по полученному списку для актуализации связей в полученном нами экземпляре Unit
|
||
var isChanged = await SyncChildSUnitAsync(unit, childsName);
|
||
|
||
if (!isChanged) onlyUpdateTransactionCount = ++onlyUpdateTransactionCount;
|
||
|
||
//logger.LogInformation($"Обработка № {i.ToString()} из {c}. Выполнено только обновление поля DateSynced - {onlyUpdateTransactionCount}");
|
||
|
||
if (onlyUpdateTransactionCount == workerSettings.CommitAfter)
|
||
{
|
||
//применяем изменения в базе данных
|
||
if (!await unitService.CommitAsync())
|
||
logger.LogError($"Не удалось изменить связи Unit после {workerSettings.CommitAfter} обновлений поля DateSynced");
|
||
else
|
||
logger.LogDebug($"----- Изменены связи Unit после {workerSettings.CommitAfter} обновлений поля DateSynced -----");
|
||
onlyUpdateTransactionCount = 0;
|
||
}
|
||
//применяем изменения в базе данных
|
||
if (isChanged && !await unitService.CommitAsync())
|
||
logger.LogError($"Не удалось изменить связи Unit {unit.Name}");
|
||
else
|
||
logger.LogDebug($"----- Изменены связи Unit: {unit.Name} -----");
|
||
}
|
||
|
||
//Удаляем детей у тех кого детей в выборке АИХ ИТ не оказалось
|
||
await RemoveWasteRelationships(groupedData);
|
||
|
||
//применяем изменения в базе данных
|
||
if (!await unitService.CommitAsync())
|
||
logger.LogError($"Не удалось удалить лишние связи");
|
||
else
|
||
logger.LogInformation($"----- Иереархические связи актуализированы -----");
|
||
}
|
||
|
||
private async Task RemoveWasteRelationships(IEnumerable<IGrouping<string?, AihitData>> groupedData)
|
||
{
|
||
var parentNames = groupedData.Select(t => t.Key);
|
||
|
||
var units = await unitService.Get()
|
||
.Include(t => t.ChildUnits).ToListAsync();
|
||
|
||
var parentsToDeleteChild = units.Where(t => parentNames.All(a => t.Name != a) && t.ChildUnits.Any());
|
||
|
||
if (parentsToDeleteChild.Any())
|
||
{
|
||
foreach (var unit in parentsToDeleteChild)
|
||
{
|
||
unit.ChildUnits.Clear();
|
||
}
|
||
}
|
||
}
|
||
|
||
private async Task<bool> SyncChildSUnitAsync(Unit unit, IEnumerable<string?> childsName)
|
||
{
|
||
var isChanged = false;
|
||
|
||
//удаляем лишние дочерние связи существующие только в БД
|
||
var childsToDelete = unit.ChildUnits.Where(t => !childsName.Any(a => t.ChildUnit?.Name.ToLower() == a!.ToLower().Trim()));
|
||
if (childsToDelete.Any())
|
||
{
|
||
DeleteChilds(unit, childsToDelete);
|
||
if (!isChanged)
|
||
isChanged = true;
|
||
}
|
||
|
||
//проверяем отсутсвующие связи
|
||
var absentChildrens = childsName.Where(c => !unit.ChildUnits.Any(x => x.ChildUnit?.Name.ToLower() == c.ToLower().Trim()));
|
||
foreach (var absentChildren in absentChildrens)
|
||
{
|
||
var childUnit = await GetUnitByNameAsync(absentChildren!);
|
||
if (childUnit == null)
|
||
{
|
||
logger.LogError($"Ошибка получения дочернего ЭК. Из базы пришел NULL для ЭК{absentChildren}");
|
||
return false;
|
||
}
|
||
|
||
unit.ChildUnits.Add(
|
||
new UnitInUnit
|
||
{
|
||
ParentUnitId = unit.Id,
|
||
ChildUnitId = childUnit.Id,
|
||
DateCreated = DateTimeOffset.UtcNow,
|
||
}
|
||
);
|
||
logger.LogInformation($"----- Создан связь Unit {unit.Name} - {childUnit.Name}-----");
|
||
|
||
if (!isChanged)
|
||
isChanged = true;
|
||
}
|
||
|
||
foreach (var child in unit.ChildUnits)
|
||
{
|
||
child.DateSynced = DateTimeOffset.UtcNow;
|
||
}
|
||
return isChanged;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Удаление дочерних связей у ЭК
|
||
/// </summary>
|
||
/// <param name="unit"></param>
|
||
/// <param name="unitToDeleteChilds"></param>
|
||
private void DeleteChilds(Unit unit, IEnumerable<UnitInUnit> unitToDeleteChilds)
|
||
{
|
||
foreach (var childUnit in unitToDeleteChilds)
|
||
{
|
||
logger.LogInformation($"----- Удаление связи Unit: {unit.Name} -----");
|
||
unit.ChildUnits.Remove(childUnit);
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Создать новый ЭК по имени
|
||
/// </summary>
|
||
/// <param name="ekName"></param>
|
||
/// <returns></returns>
|
||
private async Task<Unit?> CreateUnit(string ekName)
|
||
{
|
||
var unit = new Unit
|
||
{
|
||
Name = ekName.Trim()
|
||
};
|
||
|
||
if (!await unitService.CreateAsync(unit))
|
||
{
|
||
logger.LogError($"Не удалось создать Unit {unit.Name}");
|
||
return null;
|
||
}
|
||
else
|
||
{
|
||
logger.LogInformation($"----- Создан Unit: {unit.Name} -----");
|
||
return unit;
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Получить ЭК с дочерними связями по имени, если такого ещё нет создать
|
||
/// </summary>
|
||
/// <param name="ekName"></param>
|
||
/// <returns></returns>
|
||
private async Task<Unit?> GetUnitByNameAsync(string ekName)
|
||
{
|
||
if (!unitService.Get().AsNoTracking().Any(u => u.Name.ToLower() == ekName.ToLower().Trim()))
|
||
{
|
||
return await CreateUnit(ekName);
|
||
}
|
||
|
||
return await unitService.Get()
|
||
.Include(u => u.ChildUnits)
|
||
.ThenInclude(t => t.ChildUnit)
|
||
.FirstAsync(u => u.Name.ToLower() == ekName.ToLower().Trim());
|
||
}
|
||
}
|
||
}
|