feat(templateMatcher): Рефакторинг, основной метод синхронизации GroupedTemplateSynchronizer разбит на отдельные классы; Неиспользуемые шаблоны теперь привязываются к ЭК КОСМПЛЕКСЫ-[ЗО].
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PARR.Core.Repositories.Interfaces.Unit;
|
||||
using PARR.Core.Services.UnitFilterService.Models;
|
||||
using PARR.Domain.Entities.Job;
|
||||
using PARR.TemplateMatcher.Services.Interfaces;
|
||||
|
||||
internal class UnitInTemplateConflictMapper : IUnitInTemplateConflictMapper
|
||||
{
|
||||
private readonly ILogger<UnitInTemplateConflictMapper> logger;
|
||||
private readonly IUnitRepository unitRepository;
|
||||
private readonly IUnitKiiUnitRepository unitKiiUnitRepository;
|
||||
|
||||
|
||||
public UnitInTemplateConflictMapper(
|
||||
ILogger<UnitInTemplateConflictMapper> logger,
|
||||
IUnitRepository unitRepository,
|
||||
IUnitKiiUnitRepository unitKiiUnitRepository)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.unitRepository = unitRepository;
|
||||
this.unitKiiUnitRepository = unitKiiUnitRepository;
|
||||
}
|
||||
|
||||
|
||||
public async Task<Dictionary<Guid, List<Guid>>> BuildMappingAsync(
|
||||
IEnumerable<UnitFilterResultDto> unitFilterResults,
|
||||
Job maxJob,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
logger.LogDebug("Начало разрешения конфликтов и построения маппинга для юнитов в шаблонах.");
|
||||
|
||||
var unitFilterResultsList = unitFilterResults.ToList();
|
||||
if (!unitFilterResultsList.Any())
|
||||
return new Dictionary<Guid, List<Guid>>();
|
||||
|
||||
var potentialAssignments = new Dictionary<Guid, List<Guid>>();
|
||||
var allPotentialRelatedUnitIds = new HashSet<Guid>();
|
||||
var allUnitInTemplateIds = new HashSet<Guid>();
|
||||
|
||||
foreach (var dto in unitFilterResultsList)
|
||||
{
|
||||
var relatedUnitIds = maxJob.IsParentRelationships == true
|
||||
? dto.Children.Select(c => c.UnitId).ToList()
|
||||
: dto.Parents.Select(p => p.UnitId).ToList();
|
||||
|
||||
var unitInTemplateId = dto.Id;
|
||||
|
||||
allUnitInTemplateIds.Add(unitInTemplateId);
|
||||
allPotentialRelatedUnitIds.UnionWith(relatedUnitIds);
|
||||
|
||||
foreach (var relatedId in relatedUnitIds)
|
||||
{
|
||||
if (!potentialAssignments.TryGetValue(relatedId, out var list))
|
||||
{
|
||||
list = new List<Guid>();
|
||||
potentialAssignments[relatedId] = list;
|
||||
}
|
||||
list.Add(unitInTemplateId);
|
||||
}
|
||||
}
|
||||
|
||||
if (!allPotentialRelatedUnitIds.Any())
|
||||
return new Dictionary<Guid, List<Guid>>();
|
||||
|
||||
var relatedUnitNames = await unitRepository.Get()
|
||||
.AsNoTracking()
|
||||
.Where(u => allPotentialRelatedUnitIds.Contains(u.Id))
|
||||
.ToDictionaryAsync(u => u.Id, u => u.Name ?? u.Id.ToString(), cancellationToken);
|
||||
|
||||
// Загружаем идентификаторы КИИ через ваш реальный репозиторий
|
||||
var kiiUnitIds = new HashSet<Guid>(await unitKiiUnitRepository.Get()
|
||||
.Select(k => k.UnitId)
|
||||
.ToListAsync(cancellationToken));
|
||||
|
||||
logger.LogDebug("Загружено {KiiCount} идентификаторов КИИ юнитов для приоритезации.", kiiUnitIds.Count);
|
||||
|
||||
var unitInTemplateToBestRelatedUnit = new Dictionary<Guid, Guid>();
|
||||
|
||||
foreach (var unitInTemplateId in allUnitInTemplateIds)
|
||||
{
|
||||
var candidates = potentialAssignments
|
||||
.Where(kvp => kvp.Value.Contains(unitInTemplateId))
|
||||
.Select(kvp => kvp.Key)
|
||||
.ToList();
|
||||
|
||||
if (candidates.Count == 0) continue;
|
||||
if (candidates.Count == 1)
|
||||
{
|
||||
unitInTemplateToBestRelatedUnit[unitInTemplateId] = candidates[0];
|
||||
continue;
|
||||
}
|
||||
|
||||
var kiiCandidates = candidates.Where(id => kiiUnitIds.Contains(id)).ToList();
|
||||
var candidatesToConsider = kiiCandidates.Any() ? kiiCandidates : candidates;
|
||||
|
||||
var relationshipCounts = new Dictionary<Guid, int>();
|
||||
foreach (var candidateId in candidatesToConsider)
|
||||
{
|
||||
int totalRelationships = 0;
|
||||
foreach (var dto in unitFilterResultsList)
|
||||
{
|
||||
if (maxJob.IsParentRelationships == true && dto.Children.Any(c => c.UnitId == candidateId))
|
||||
totalRelationships += dto.Children.Count;
|
||||
else if (maxJob.IsParentRelationships == false && dto.Parents.Any(p => p.UnitId == candidateId))
|
||||
totalRelationships += dto.Parents.Count;
|
||||
}
|
||||
relationshipCounts[candidateId] = totalRelationships;
|
||||
}
|
||||
|
||||
var bestCandidate = candidatesToConsider[0];
|
||||
int bestCount = relationshipCounts[bestCandidate];
|
||||
|
||||
foreach (var candidateId in candidatesToConsider.Skip(1))
|
||||
{
|
||||
int currentCount = relationshipCounts[candidateId];
|
||||
if (currentCount > bestCount ||
|
||||
(currentCount == bestCount && string.Compare(
|
||||
relatedUnitNames.GetValueOrDefault(candidateId, candidateId.ToString()),
|
||||
relatedUnitNames.GetValueOrDefault(bestCandidate, bestCandidate.ToString()),
|
||||
StringComparison.OrdinalIgnoreCase) < 0))
|
||||
{
|
||||
bestCandidate = candidateId;
|
||||
bestCount = currentCount;
|
||||
}
|
||||
}
|
||||
|
||||
unitInTemplateToBestRelatedUnit[unitInTemplateId] = bestCandidate;
|
||||
}
|
||||
|
||||
logger.LogDebug("Разрешение конфликтов завершено. Найдено {Count} однозначных назначений.", unitInTemplateToBestRelatedUnit.Count);
|
||||
|
||||
var reverseMapping = new Dictionary<Guid, List<Guid>>();
|
||||
foreach (var kvp in unitInTemplateToBestRelatedUnit)
|
||||
{
|
||||
if (!reverseMapping.TryGetValue(kvp.Value, out var list))
|
||||
{
|
||||
list = new List<Guid>();
|
||||
reverseMapping[kvp.Value] = list;
|
||||
}
|
||||
list.Add(kvp.Key);
|
||||
}
|
||||
|
||||
return reverseMapping;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user