feat(aihitSyncer): RemoveFromCacheAsync после обновления атрибутов ЭК

This commit is contained in:
Mikhail Kuznetsov
2026-06-04 14:14:10 +10:00
parent 1f4d338422
commit 0e8dea4c48
4 changed files with 105 additions and 109 deletions

View File

@@ -1,9 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using PARR.AIHITMainSyncer.Settings;
using PARR.Core.Common.Interfaces;
using PARR.Core.Repositories.Interfaces.Unit;
using PARR.Core.Services.UnitService.Interfaces;
using PARR.Domain.Common.Rabbit.Messages;
using PARR.Domain.Entities.Unit;
@@ -13,26 +13,29 @@ namespace PARR.AIHITMainSyncer.Services
{
private readonly ILogger<SyncerService> logger;
private readonly ITransformService transformService;
private readonly IUnitRepository unitService;
private readonly IUnitFieldRepository unitFieldService;
private readonly IUnitFieldValueRepository unitFieldValueService;
private readonly IUnitRepository unitRepository;
private readonly IUnitFieldRepository unitFieldRepository;
private readonly IUnitFieldValueRepository unitFieldValueRepository;
private readonly FieldValueReplacementsSettings fieldValueReplacementsSettings;
private readonly IUnitService unitService;
public SyncerService(
ILogger<SyncerService> logger,
ITransformService transformService,
IUnitRepository unitService,
IUnitFieldRepository unitFieldService,
IUnitFieldValueRepository unitFieldValueService,
FieldValueReplacementsSettings fieldValueReplacementsSettings
IUnitRepository unitRepository,
IUnitFieldRepository unitFieldRepository,
IUnitFieldValueRepository unitFieldValueRepository,
FieldValueReplacementsSettings fieldValueReplacementsSettings,
IUnitService unitService
)
{
this.logger = logger;
this.transformService = transformService;
this.unitService = unitService;
this.unitFieldService = unitFieldService;
this.unitFieldValueService = unitFieldValueService;
this.unitRepository = unitRepository;
this.unitFieldRepository = unitFieldRepository;
this.unitFieldValueRepository = unitFieldValueRepository;
this.fieldValueReplacementsSettings = fieldValueReplacementsSettings;
this.unitService = unitService;
}
@@ -45,7 +48,6 @@ namespace PARR.AIHITMainSyncer.Services
logger.LogWarning("Не удалось десериализовать сообщение в объект AihitMainDataMq. Сообщение: {Message}", msg);
return;
}
await SyncUnitAsync(objFromQuery);
}
@@ -55,7 +57,7 @@ namespace PARR.AIHITMainSyncer.Services
logger.LogDebug("Начинаем синхронизацию Unit для объекта с именем: {UnitName}", objFromQuery.Name);
//Получаем сразу словарь атрибутов, чтобы не ходить каждый раз в базу
var fieldsFromDB = await unitFieldService.Get().AsNoTracking().ToListAsync();
var fieldsFromDB = await unitFieldRepository.Get().AsNoTracking().ToListAsync();
if (!objFromQuery.Properties.Any())
{
@@ -63,24 +65,24 @@ namespace PARR.AIHITMainSyncer.Services
return;
}
// 1. Создаем копию и нормализуем свойства (удаляем лишние пробелы)
// 1. Создаем копию и нормализуем свойства
var normalizedProperties = new Dictionary<string, string?>();
foreach (var kvp in objFromQuery.Properties)
normalizedProperties[kvp.Key.Trim()] = kvp.Value?.Trim();
// 2. Применяем замены значений к нормализованным свойствам
// 2. Применяем замены значений
ApplyFieldValueReplacements(normalizedProperties);
var listAihitData = new List<KeyValuePair<string, string?>>();
// 3. Обрабатываем простые значения из нормализованных свойств
// 3. Обрабатываем простые значения
var propertisWithSimpleValues = normalizedProperties
.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);
// 4. Обрабатываем множественные значения из нормализованных свойств
// 4. Обрабатываем множественные значения
var propertiesWithMultipleValues = objFromQuery.Properties.Where(t => !propertisWithSimpleValues.Any(a => t.Key.Trim() == a.Key)).ToList();
propertiesWithMultipleValues.ForEach(p => listAihitData.AddRange(
@@ -110,10 +112,13 @@ namespace PARR.AIHITMainSyncer.Services
)
.ToList();
bool hasChanges = false;
if (unitValuesToRemove.Any())
{
logger.LogDebug("Удаляем {Count} устаревших значений для Unit {UnitName}", unitValuesToRemove.Count, unit.Name);
unitValuesToRemove.ForEach(uv => unit.UnitValues.Remove(uv));
hasChanges = true;
}
var unitValueMissing = listAihitData.Where(t =>
@@ -130,7 +135,6 @@ namespace PARR.AIHITMainSyncer.Services
var valuesInChanges = unitValueMissing.Select(s => s.Value).Distinct().ToList();
await SyncFieldsAsync(fieldsInChanges!, fieldsFromDB);
await SyncValuesAsync(valuesInChanges);
var normalizedFieldNames = fieldsInChanges
@@ -138,7 +142,7 @@ namespace PARR.AIHITMainSyncer.Services
.Where(n => n != null)
.ToHashSet(StringComparer.OrdinalIgnoreCase);
var fieldsNameWithId = await unitFieldService.Get().AsNoTracking()
var fieldsNameWithId = await unitFieldRepository.Get().AsNoTracking()
.Where(f => normalizedFieldNames.Contains(f.AihitName))
.ToListAsync();
@@ -147,7 +151,7 @@ namespace PARR.AIHITMainSyncer.Services
.Select(v => v!.Trim())
.ToHashSet(StringComparer.OrdinalIgnoreCase);
var valuesWithId = await unitFieldValueService.Get().AsNoTracking()
var valuesWithId = await unitFieldValueRepository.Get().AsNoTracking()
.Where(v =>
(v.Value == null && valuesInChanges.Contains(null)) ||
(v.Value != null && normalizedValues.Contains(v.Value)))
@@ -156,17 +160,23 @@ namespace PARR.AIHITMainSyncer.Services
foreach (var change in unitValueMissing)
ApplyChange(unit, fieldsNameWithId, valuesWithId, change);
if (!await unitService.CommitAsync())
hasChanges = true;
}
else
logger.LogDebug("Нет новых значений для синхронизации для Unit {UnitName}", unit.Name);
// Сохраняем изменения и инвалидируем кэш только если были реальные изменения
if (hasChanges)
{
if (!await unitRepository.CommitAsync())
{
logger.LogError("Не удалось применить изменения по актуализиции аттрибуто Unit {UnitName} в базе данных", unit.Name);
logger.LogError("Не удалось применить изменения по актуализации атрибутов Unit {UnitName} в базе данных", unit.Name);
return;
}
logger.LogInformation("Успешно обновлены атрибуты для Unit {UnitName}. Добавлено {AddedCount} значений", unit.Name, unitValueMissing.Count);
}
else
{
logger.LogDebug("Нет новых значений для синхронизации для Unit {UnitName}", unit.Name);
// Инвалидация кэша после успешного сохранения
await unitService.RemoveFromCacheAsync(unit.Id);
logger.LogInformation("Успешно обновлены атрибуты для Unit {UnitName}. Кэш инвалидирован.", unit.Name);
}
logger.LogInformation("Завершена синхронизация Unit {UnitName}", unit.Name);
@@ -191,7 +201,6 @@ namespace PARR.AIHITMainSyncer.Services
bool isTagProperty = tagUnitField != null && multiValueProperty.Key == tagUnitField.AihitName;
string[] splitValues;
if (isTagProperty)
{
// Для тегов нормализуем разделители до пробела
@@ -249,10 +258,9 @@ namespace PARR.AIHITMainSyncer.Services
}
private async Task SyncValuesAsync(List<string?> values)
private async Task SyncValuesAsync(List<string?> values)
{
bool hasNull = values.Any(v => v is null);
// все поля из АИХИТ
var normalizedNoneNullValues = values
.Where(v => v != null)
.Select(v => v!.Trim())
@@ -261,8 +269,7 @@ namespace PARR.AIHITMainSyncer.Services
logger.LogDebug("Синхронизируем {Count} значений (включая null: {HasNull})", normalizedNoneNullValues.Count, hasNull);
// Получаем существующие значения из БД
var existingValuesInDb = await unitFieldValueService.Get()
var existingValuesInDb = await unitFieldValueRepository.Get()
.Where(v => normalizedNoneNullValues.Contains(v.Value!) || v.Value == null)
.Select(v => v.Value)
.ToListAsync();
@@ -287,35 +294,22 @@ namespace PARR.AIHITMainSyncer.Services
return;
}
// Создаём сущности — сохраняем оригинальный регистр из nonNullValues!
// (для null — просто null)
var newFieldValues = newValuesToInsert.Select(v =>
new UnitFieldValue
{
Id = Guid.NewGuid(),
Value = v // ← v — уже trim()-нутый non-null, или null
Value = v
})
.ToList();
if (!await unitFieldValueService.AddRangeAsync(newFieldValues) || !await unitFieldValueService.CommitAsync())
// Только добавляем в контекст, НЕ коммитим
if (!await unitFieldValueRepository.AddRangeAsync(newFieldValues))
{
logger.LogError(
"Не удалось сохранить {Count} новых значений FieldValues",
newValuesToInsert.Count);
logger.LogError("Не удалось добавить {Count} новых значений FieldValues в контекст", newValuesToInsert.Count);
}
else
{
if (newValuesToInsert.Count <= 10)
{
var preview = string.Join(", ", newValuesToInsert.Select(v => v ?? "<null>"));
logger.LogInformation("Добавлено {Count} значений FieldValues: [{Values}]", newValuesToInsert.Count, preview);
}
else
{
logger.LogInformation("Добавлено {Count} значений FieldValues (первые 5: {Preview})",
newValuesToInsert.Count,
string.Join(", ", newValuesToInsert.Take(5).Select(v => v ?? "<null>")));
}
logger.LogDebug("Подготовлено {Count} новых значений FieldValues для сохранения", newValuesToInsert.Count);
}
}
@@ -341,24 +335,16 @@ namespace PARR.AIHITMainSyncer.Services
EsppName = null,
};
if (!await unitFieldService.CreateAsync(field))
// Только добавляем в контекст, НЕ коммитим
if (!await unitFieldRepository.CreateAsync(field))
{
logger.LogError("Не удалось создать запись в таблице Fields: {FieldName}", item);
logger.LogError("Не удалось добавить поле в контекст: {FieldName}", item);
}
else
{
logger.LogInformation("Создана запись в таблице Fields: {FieldName}", item);
logger.LogDebug("Подготовлено поле для сохранения: {FieldName}", item);
}
}
if (!await unitFieldService.CommitAsync())
{
logger.LogError("Не удалось применить изменения по добавлению новых Fields в базе данных");
}
else
{
logger.LogDebug("Успешно зафиксированы изменения по добавлению новых Fields");
}
}
@@ -393,7 +379,7 @@ namespace PARR.AIHITMainSyncer.Services
{
var unit = new Unit { Name = name.Trim().ToUpperInvariant() };
if (!await unitService.CreateAsync(unit) || !await unitService.CommitAsync())
if (!await unitRepository.CreateAsync(unit) || !await unitRepository.CommitAsync())
{
logger.LogError("Не удалось создать Unit {UnitName}", unit.Name);
throw new InvalidOperationException($"Не удалось создать Unit {unit.Name}");
@@ -402,7 +388,6 @@ namespace PARR.AIHITMainSyncer.Services
{
logger.LogInformation("Создан Unit: {UnitName}", unit.Name);
}
return unit;
}
@@ -417,7 +402,7 @@ namespace PARR.AIHITMainSyncer.Services
private IQueryable<Unit> GetUnitWithFieldsAndValues()
{
return unitService.Get()
return unitRepository.Get()
.Include(t => t.UnitValues)
.ThenInclude(uv => uv.Field)
.Include(t => t.UnitValues)
@@ -442,7 +427,6 @@ namespace PARR.AIHITMainSyncer.Services
replacement.FieldName, currentValue, replacement.NewValue);
properties[replacement.FieldName] = replacement.NewValue;
}
}
}
}