Files
parr_api/PARR.AIHITRelationshipsSyncer/Services/Implementations/RelationshipsSyncSrevice.cs

213 lines
8.8 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 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).Select(t => t.ChildEk);
//Проходим циклом по полученному списку для актуализации связей в полученном нами экземпляре 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());
}
}
}