feat(dal): уточнена логика получение имени связанных ЭК, переписано кэширование МАКС:FIELD, в синхронизацию и контролер заданий роботов добавлены include
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
namespace PARR.DAL.DomainServices.Shortcodes.Models
|
||||
{
|
||||
internal class CachedGroupedShortCode
|
||||
{
|
||||
public string Value { get; set; } = string.Empty;
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
public string? Source { get; set; } = "ShortcodesService";
|
||||
public int Version { get; set; } = 1;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PARR.Constants;
|
||||
using PARR.DAL.CacheServices;
|
||||
using PARR.DAL.Contracts;
|
||||
using PARR.DAL.DomainModels;
|
||||
using PARR.DAL.DomainServices.Interfaces;
|
||||
@@ -31,7 +32,7 @@ namespace PARR.DAL.DomainServices.Shortcodes
|
||||
private readonly IUnitInValueService unitInValueService;
|
||||
private readonly IUnitFieldService unitFieldService;
|
||||
private readonly ITemplateService templateService;
|
||||
private readonly IGroupedShortcodesCacheService groupedShortcodesCacheService;
|
||||
private readonly IRedisCacheService cacheService;
|
||||
private readonly IUnitFilterService unitFilterService;
|
||||
|
||||
public ShortcodesService(
|
||||
@@ -43,7 +44,7 @@ namespace PARR.DAL.DomainServices.Shortcodes
|
||||
IUnitInValueService unitInValueService,
|
||||
IUnitFieldService unitFieldService,
|
||||
ITemplateService templateService,
|
||||
IGroupedShortcodesCacheService groupedShortcodesCacheService
|
||||
IRedisCacheService cacheService
|
||||
)
|
||||
{
|
||||
this.logger = logger;
|
||||
@@ -53,7 +54,7 @@ namespace PARR.DAL.DomainServices.Shortcodes
|
||||
this.unitInValueService = unitInValueService;
|
||||
this.unitFieldService = unitFieldService;
|
||||
this.templateService = templateService;
|
||||
this.groupedShortcodesCacheService = groupedShortcodesCacheService;
|
||||
this.cacheService = cacheService;
|
||||
this.unitFilterService = unitFilterService;
|
||||
}
|
||||
|
||||
@@ -124,8 +125,7 @@ namespace PARR.DAL.DomainServices.Shortcodes
|
||||
var maxShortcodes = Regex.Matches(resultName, maxShortcodePattern);
|
||||
if (maxShortcodes.Count > 0)
|
||||
{
|
||||
var unitIds = template.UnitsInTemplate.Select(uit => uit.UnitId).ToList();
|
||||
resultName = await ReplaceMaxShortcodesAsync(job.Group.Id, template.UnitId, unitIds, resultName, maxShortcodes);
|
||||
resultName = await ReplaceMaxShortcodesAsync(job.Group.Id, template.UnitId, resultName, maxShortcodes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,9 +273,6 @@ namespace PARR.DAL.DomainServices.Shortcodes
|
||||
new ShortcodeInfoDto { Shortcode = "%МАКС:ИМЯ АТРИБУТА%",
|
||||
Description = "Используется только с групповым типом работ. Наиболее часто встречающееся значение поля в группе (игнорирует пустые). Пример: %МАКС:РАБОЧАЯ_ГР_ОТВ_ЗА_ЭК%",
|
||||
Type = ShortcodeTypeEnum.Standart },
|
||||
new ShortcodeInfoDto { Shortcode = "%ГР_ПОЛЕ-ПН%",
|
||||
Description = "Нумерованный список unit-ов из шаблона: 1. ЭК-123 (Значение1, Значение2). Использует GroupingUnitFieldId из JobGroup.",
|
||||
Type = ShortcodeTypeEnum.Relationship },
|
||||
new ShortcodeInfoDto{ Shortcode = "%БУКВЫ:ИМЯ АТРИБУТА%",
|
||||
Description = "Извлекает только буквы из значения поля. Пример: %БУКВЫ:ЗОНА_ОТВЕТСТВЕННОСТИ% → ПРИВ",
|
||||
Type = ShortcodeTypeEnum.Standart
|
||||
@@ -290,7 +287,10 @@ namespace PARR.DAL.DomainServices.Shortcodes
|
||||
Type = ShortcodeTypeEnum.Relationship },
|
||||
new ShortcodeInfoDto { Shortcode = "%СВЯЗИ-ПН%",
|
||||
Description = "Связанные ЭК с нумерацией (1. ..., 2. ...), выбираются только при настроенном фильтре по полям в связанных ЭК",
|
||||
Type = ShortcodeTypeEnum.Relationship }
|
||||
Type = ShortcodeTypeEnum.Relationship },
|
||||
new ShortcodeInfoDto { Shortcode = "%ГР_ПОЛЕ-ПН%",
|
||||
Description = "Нумерованный список unit-ов из шаблона: 1. ЭК-123 (Значение1, Значение2). Использует GroupingUnitFieldId из JobGroup.",
|
||||
Type = ShortcodeTypeEnum.Relationship },
|
||||
});
|
||||
|
||||
// 4. Все доступные поля из UnitField
|
||||
@@ -363,7 +363,7 @@ namespace PARR.DAL.DomainServices.Shortcodes
|
||||
return resultName;
|
||||
}
|
||||
|
||||
private async Task<string> ReplaceMaxShortcodesAsync(Guid jobGroupId, Guid unitId, List<Guid> unitIds, string input, MatchCollection maxShortcodes)
|
||||
private async Task<string> ReplaceMaxShortcodesAsync(Guid jobGroupId, Guid unitId, string input, MatchCollection maxShortcodes)
|
||||
{
|
||||
var shortcodeToMatches = maxShortcodes
|
||||
.Cast<Match>()
|
||||
@@ -379,56 +379,69 @@ namespace PARR.DAL.DomainServices.Shortcodes
|
||||
logger.LogDebug("Обработка {Shortcode} для JobGroup {JobGroupId}, Template.UnitId {UnitId}, fieldName {FieldName}",
|
||||
fullShortcode, jobGroupId, unitId, fieldName);
|
||||
|
||||
var mostFrequentValue = await groupedShortcodesCacheService.GetAggregatedValueAsync(
|
||||
jobGroupId,
|
||||
unitId,
|
||||
fullShortcode,
|
||||
async () =>
|
||||
{
|
||||
logger.LogDebug("Кэш промахнут для {Shortcode}, начинаем вычисление.", fullShortcode);
|
||||
|
||||
// ✅ Пытаемся загрузить UnitsInTemplate из БД
|
||||
var dbUnitIds = await jobService.Get()
|
||||
.Where(j => j.GroupId == jobGroupId)
|
||||
.Join(
|
||||
templateService.Get()
|
||||
.Where(t => t.StatusTypeId == TemplateStatusTypeEnum.Used)
|
||||
.Include(t => t.UnitsInTemplate),
|
||||
job => job.Id,
|
||||
template => template.JobId,
|
||||
(job, template) => template
|
||||
)
|
||||
.SelectMany(template => template.UnitsInTemplate)
|
||||
.Select(uit => uit.UnitId)
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
logger.LogDebug("Загружено {Count} unitIds из БД для JobGroup {JobGroupId}", dbUnitIds.Count, jobGroupId);
|
||||
|
||||
// ✅ Если в БД нет UnitsInTemplate — используем переданные unitIds
|
||||
var effectiveUnitIds = dbUnitIds.Any() ? dbUnitIds : unitIds;
|
||||
|
||||
logger.LogDebug("EffectiveUnitIds: [{Ids}], Count: {Count}", string.Join(", ", effectiveUnitIds), effectiveUnitIds.Count);
|
||||
|
||||
// Вызываем метод из сервиса
|
||||
var result = await unitInValueService.GetMostFrequentValueForFieldAsync(effectiveUnitIds, fieldName);
|
||||
|
||||
logger.LogDebug("Результат GetMostFrequentValueForFieldAsync: {Result}, для поля {FieldName}, unitIds: [{Ids}]", result, fieldName, string.Join(", ", effectiveUnitIds));
|
||||
|
||||
return result ?? string.Empty;
|
||||
});
|
||||
|
||||
logger.LogDebug("Итоговое значение для {Shortcode}: {Value}", fullShortcode, mostFrequentValue);
|
||||
var mostFrequentValue = await GetMaxShortCodeFromCacheOrDbAsync(jobGroupId, unitId, fullShortcode, fieldName);
|
||||
|
||||
foreach (var match in matches)
|
||||
{
|
||||
input = input.Replace(match.Value, mostFrequentValue);
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
private async Task<string> GetMaxShortCodeFromCacheOrDbAsync(Guid jobGroupId, Guid unitId, string fullShortcode, string fieldName)
|
||||
{
|
||||
var cacheKey = $"gr_shcd_{jobGroupId:N}_{unitId:N}_{ComputeHash(fullShortcode)}";
|
||||
|
||||
var cachedData = await cacheService.GetCachedDataAsync<CachedGroupedShortCode>(cacheKey);
|
||||
if (cachedData != null)
|
||||
{
|
||||
logger.LogDebug("Кэш попал для GroupedShortCode '{Name}': {Value}", fullShortcode, cachedData.Value);
|
||||
return cachedData.Value;
|
||||
}
|
||||
|
||||
logger.LogDebug("Кэш промахнут для GroupedShortCode '{Name}'. Запрашиваем из БД.", fullShortcode);
|
||||
|
||||
// Загружаем юниты из БД
|
||||
var effectiveUnitIds = await jobService.Get()
|
||||
.Where(j => j.GroupId == jobGroupId)
|
||||
.Join(
|
||||
templateService.Get()
|
||||
.Where(t => t.StatusTypeId == TemplateStatusTypeEnum.Used && t.UnitId == unitId)
|
||||
.Include(t => t.UnitsInTemplate),
|
||||
job => job.Id,
|
||||
template => template.JobId,
|
||||
(job, template) => template
|
||||
)
|
||||
.SelectMany(template => template.UnitsInTemplate)
|
||||
.Select(uit => uit.UnitId)
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
logger.LogDebug("EffectiveUnitIds: [{Ids}], Count: {Count}", string.Join(", ", effectiveUnitIds), effectiveUnitIds.Count);
|
||||
|
||||
// Вызываем метод из сервиса
|
||||
var mostFrequentValue = await unitInValueService.GetMostFrequentValueForFieldAsync(effectiveUnitIds, fieldName);
|
||||
|
||||
logger.LogDebug("Результат GetMostFrequentValueForFieldAsync: {Result}, для поля {FieldName}, unitIds: [{Ids}]", mostFrequentValue, fieldName, string.Join(", ", effectiveUnitIds));
|
||||
|
||||
// Не кэшируем пустые значения
|
||||
if (!string.IsNullOrEmpty(mostFrequentValue))
|
||||
{
|
||||
var toCache = new CachedGroupedShortCode
|
||||
{
|
||||
Value = mostFrequentValue,
|
||||
Timestamp = DateTimeOffset.UtcNow,
|
||||
Source = GetType().Name,
|
||||
Version = 1
|
||||
};
|
||||
|
||||
await cacheService.SetCachedDataAsync(cacheKey, toCache, TimeSpan.FromHours(1));
|
||||
return mostFrequentValue;
|
||||
}
|
||||
|
||||
return "Нет данных";
|
||||
}
|
||||
|
||||
private async Task<string> ReplaceLettersShortcodesAsync(Guid unitId, string input, MatchCollection lettersShortcodes)
|
||||
{
|
||||
var shortcodeToMatches = lettersShortcodes
|
||||
@@ -485,5 +498,12 @@ namespace PARR.DAL.DomainServices.Shortcodes
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
private static string ComputeHash(string input)
|
||||
{
|
||||
using var sha256 = System.Security.Cryptography.SHA256.Create();
|
||||
var hashedBytes = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(input));
|
||||
return Convert.ToBase64String(hashedBytes).Replace('+', '-').Replace('/', '_').Substring(0, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user