Merge branch 'template-rename-pending' into dev

# Conflicts:
#	PARR.DAL/Repositories/TemplateRepository.cs
This commit is contained in:
Mikhail Trubnikov
2026-07-27 09:06:36 +10:00
27 changed files with 933 additions and 292 deletions

View File

@@ -15,23 +15,13 @@ namespace PARR.DAL.Repositories.Base
{
internal abstract class BaseRepository<T> : IBaseRepository<T> where T : class, IBaseEntity
{
//private readonly ILogger<BaseRepository<T>> logger;
//protected abstract DbSet<T> EntitySet { get; }
//protected abstract DataContext EntitiContext { get; }
//public BaseRepository(ILogger<BaseRepository<T>> logger)
//{
// this.logger = logger;
//}
protected readonly ILogger logger;
protected readonly ILogger _logger;
protected readonly DbSet<T> EntitySet;
protected readonly DataContext EntityContext;
protected BaseRepository(ILogger logger, DataContext dataContext)
{
this.logger = logger;
this._logger = logger;
this.EntityContext = dataContext;
this.EntitySet = dataContext.Set<T>();
}
@@ -39,7 +29,7 @@ namespace PARR.DAL.Repositories.Base
public virtual async Task<bool> AddRangeAsync(List<T> objs)
{
logger.LogDebug("Начинаю добавление диапазона объектов типа {EntityType}, количество: {Count}",
_logger.LogDebug("Начинаю добавление диапазона объектов типа {EntityType}, количество: {Count}",
typeof(T).Name, objs.Count);
objs.ForEach(item => item.DateCreated = DateTimeOffset.UtcNow);
@@ -47,26 +37,26 @@ namespace PARR.DAL.Repositories.Base
try
{
await EntitySet.AddRangeAsync(objs);
logger.LogDebug("Успешно добавлено {Count} объектов типа {EntityType}",
_logger.LogDebug("Успешно добавлено {Count} объектов типа {EntityType}",
objs.Count, typeof(T).Name);
return true;
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка при добавлении диапазона объектов типа {EntityType}", typeof(T).Name);
_logger.LogError(ex, "Ошибка при добавлении диапазона объектов типа {EntityType}", typeof(T).Name);
return false;
}
}
public async Task<bool> CommitAsync(IHistoryInitiator? initiator = null)
{
logger.LogDebug("Начинаю сохранение изменений в БД для объектов типа {EntityType}", typeof(T).Name);
_logger.LogDebug("Начинаю сохранение изменений в БД для объектов типа {EntityType}", typeof(T).Name);
#region Изменения
var modifiedEntrities = EntityContext.ChangeTracker.Entries()
.Where(t => t.State == EntityState.Modified/* || t.State == EntityState.Deleted*/);
logger.LogDebug("Найдено {Count} измененных сущностей для обработки истории", modifiedEntrities.Count());
_logger.LogDebug("Найдено {Count} измененных сущностей для обработки истории", modifiedEntrities.Count());
foreach (var obj in modifiedEntrities)
{
@@ -83,13 +73,13 @@ namespace PARR.DAL.Repositories.Base
try
{
var changedCount = await EntityContext.SaveChangesAsync();
logger.LogDebug("Успешно сохранено {ChangedCount} изменений в БД для объектов типа {EntityType}",
_logger.LogDebug("Успешно сохранено {ChangedCount} изменений в БД для объектов типа {EntityType}",
changedCount, typeof(T).Name);
return true;
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка при сохранении изменений в БД для объектов типа {EntityType}", typeof(T).Name);
_logger.LogError(ex, "Ошибка при сохранении изменений в БД для объектов типа {EntityType}", typeof(T).Name);
return false;
}
}
@@ -104,14 +94,14 @@ namespace PARR.DAL.Repositories.Base
if (initiator == null)
return;
logger.LogDebug("Устанавливаю инициатора для изменений");
_logger.LogDebug("Устанавливаю инициатора для изменений");
// Задаем инициатора только для новых и измененных записей
var entrities = EntityContext.ChangeTracker.Entries()
.Where(t => t.State == EntityState.Modified || t.State == EntityState.Added);
var entityCount = entrities.Count();
logger.LogDebug("Найдено {Count} сущностей для установки инициатора", entityCount);
_logger.LogDebug("Найдено {Count} сущностей для установки инициатора", entityCount);
// смотрим есть ли у объекта интерфейс IHistoryInitiator, если есть, задаём значения
foreach (var obj in entrities)
@@ -123,7 +113,7 @@ namespace PARR.DAL.Repositories.Base
(obj.Entity as IHistoryInitiator)!.InitiatorParrComponentId = initiator?.InitiatorParrComponentId ?? null;
(obj.Entity as IHistoryInitiator)!.InitiatorComment = initiator?.InitiatorComment ?? null;
logger.LogDebug("Установлен инициатор для сущности типа {EntityType}", obj.Entity.GetType().Name);
_logger.LogDebug("Установлен инициатор для сущности типа {EntityType}", obj.Entity.GetType().Name);
}
}
}
@@ -150,12 +140,12 @@ namespace PARR.DAL.Repositories.Base
if (!isManual)
{
logger.LogDebug("Обновляю DateModified для сущности типа {EntityType}", obj.Entity.GetType().Name);
_logger.LogDebug("Обновляю DateModified для сущности типа {EntityType}", obj.Entity.GetType().Name);
entity.DateModified = DateTimeOffset.UtcNow;
}
else
{
logger.LogDebug("Пропуск обновления DateModified (ManualControl) для {EntityType}", entityType.Name);
_logger.LogDebug("Пропуск обновления DateModified (ManualControl) для {EntityType}", entityType.Name);
}
}
}
@@ -166,7 +156,7 @@ namespace PARR.DAL.Repositories.Base
/// <param name="obj"></param>
private void TableHistoryResolver(EntityEntry obj)
{
logger.LogDebug("Проверяю необходимость создания истории для сущности типа {EntityType}", obj.Entity.GetType().Name);
_logger.LogDebug("Проверяю необходимость создания истории для сущности типа {EntityType}", obj.Entity.GetType().Name);
var myHistoryInterface = obj.Entity.GetType().GetInterfaces()
.Where(t => t.IsGenericType)
@@ -176,7 +166,7 @@ namespace PARR.DAL.Repositories.Base
// у этого объекта нет интерфейса IMyHistory<>. Не ведем историю
if (myHistoryInterface == null)
{
logger.LogDebug("Сущность типа {EntityType} не требует ведения истории", obj.Entity.GetType().Name);
_logger.LogDebug("Сущность типа {EntityType} не требует ведения истории", obj.Entity.GetType().Name);
return;
}
@@ -186,13 +176,13 @@ namespace PARR.DAL.Repositories.Base
var historyType = myHistoryInterface.GetGenericArguments().First();
var historyProps = historyType.GetProperties(/*BindingFlags.DeclaredOnly | */ /*BindingFlags.Public*/).ToList();
logger.LogDebug("Создаю историю для сущности типа {EntityType}, тип истории: {HistoryType}",
_logger.LogDebug("Создаю историю для сущности типа {EntityType}, тип истории: {HistoryType}",
obj.Entity.GetType().Name, historyType.Name);
var historyInstance = Activator.CreateInstance(historyType);
if (historyInstance == null)
{
logger.LogError("Не смог создать инстанс для ведения истории {HistoryType}", historyType.Name);
_logger.LogError("Не смог создать инстанс для ведения истории {HistoryType}", historyType.Name);
return;
}
@@ -208,11 +198,11 @@ namespace PARR.DAL.Repositories.Base
try
{
EntityContext.Add(historyInstance);
logger.LogDebug("История добавлена для сущности типа {EntityType}", obj.Entity.GetType().Name);
_logger.LogDebug("История добавлена для сущности типа {EntityType}", obj.Entity.GetType().Name);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка при добавлении объекта в историю {HistoryType}", historyType.Name);
_logger.LogError(ex, "Ошибка при добавлении объекта в историю {HistoryType}", historyType.Name);
}
}
@@ -225,7 +215,7 @@ namespace PARR.DAL.Repositories.Base
/// <param name="propsList"></param>
private void FillHistoryProps(EntityEntry originalObj, ref object historyInstance, List<PropertyInfo> propsList)
{
logger.LogDebug("Заполняю историю для сущности типа {EntityType}", originalObj.Entity.GetType().Name);
_logger.LogDebug("Заполняю историю для сущности типа {EntityType}", originalObj.Entity.GetType().Name);
foreach (var prop in propsList)
{
@@ -250,7 +240,7 @@ namespace PARR.DAL.Repositories.Base
histProp.SetValue(historyInstance, origValues);
}
logger.LogDebug("Завершено заполнение истории для сущности типа {EntityType}", originalObj.Entity.GetType().Name);
_logger.LogDebug("Завершено заполнение истории для сущности типа {EntityType}", originalObj.Entity.GetType().Name);
}
@@ -266,14 +256,14 @@ namespace PARR.DAL.Repositories.Base
var histProp = instanceObj.GetType().GetProperty(propName);
if (histProp == null)
{
logger.LogError("При изменении объекта для БД, не найдено свойство {PropertyName}", propName);
_logger.LogError("При изменении объекта для БД, не найдено свойство {PropertyName}", propName);
return;
}
// сравним типы
if (histProp.PropertyType != typeof(TValue))
{
logger.LogError("При изменении объекта для БД, не совпадают типы у свойства {PropertyName}, {PropertyType}!={ValueType}",
_logger.LogError("При изменении объекта для БД, не совпадают типы у свойства {PropertyName}, {PropertyType}!={ValueType}",
propName, histProp.PropertyType.Name, typeof(TValue).Name);
return;
}
@@ -340,7 +330,7 @@ namespace PARR.DAL.Repositories.Base
public virtual async Task<bool> CreateAsync(T obj)
{
logger.LogDebug("Начинаю создание объекта типа {EntityType}", typeof(T).Name);
_logger.LogDebug("Начинаю создание объекта типа {EntityType}", typeof(T).Name);
if (obj.DateCreated == DateTimeOffset.MinValue)
obj.DateCreated = DateTimeOffset.UtcNow;
@@ -348,73 +338,73 @@ namespace PARR.DAL.Repositories.Base
try
{
await EntitySet.AddAsync(obj);
logger.LogDebug("Объект типа {EntityType} добавлен в контекст", typeof(T).Name);
_logger.LogDebug("Объект типа {EntityType} добавлен в контекст", typeof(T).Name);
return true;
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка при добавлении объекта типа {EntityType} в БД", typeof(T).Name);
_logger.LogError(ex, "Ошибка при добавлении объекта типа {EntityType} в БД", typeof(T).Name);
return false;
}
}
public virtual bool Delete(T obj)
{
logger.LogDebug("Начинаю удаление объекта типа {EntityType}", obj.GetType().Name);
_logger.LogDebug("Начинаю удаление объекта типа {EntityType}", obj.GetType().Name);
try
{
EntitySet.Remove(obj);
logger.LogDebug("Объект типа {EntityType} удален из контекста", obj.GetType().Name);
_logger.LogDebug("Объект типа {EntityType} удален из контекста", obj.GetType().Name);
return true;
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка при удалении объекта типа {EntityType} из БД", obj.GetType().Name);
_logger.LogError(ex, "Ошибка при удалении объекта типа {EntityType} из БД", obj.GetType().Name);
return false;
}
}
public virtual async Task<bool> DeleteAsync(Guid id)
{
logger.LogDebug("Начинаю удаление объекта типа {EntityType} по ID: {Id}", typeof(T).Name, id);
_logger.LogDebug("Начинаю удаление объекта типа {EntityType} по ID: {Id}", typeof(T).Name, id);
try
{
var exist = await GetAsync(id);
if (exist == null)
{
logger.LogError("Ошибка при удалении из БД. Не найдена запись в БД типа {EntityType} с id: {Id}",
_logger.LogError("Ошибка при удалении из БД. Не найдена запись в БД типа {EntityType} с id: {Id}",
typeof(T).Name, id);
return false;
}
EntitySet.Remove(exist);
logger.LogDebug("Объект типа {EntityType} с ID {Id} удален из контекста", typeof(T).Name, id);
_logger.LogDebug("Объект типа {EntityType} с ID {Id} удален из контекста", typeof(T).Name, id);
return true;
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка при удалении объекта типа {EntityType} из БД по ID: {Id}", typeof(T).Name, id);
_logger.LogError(ex, "Ошибка при удалении объекта типа {EntityType} из БД по ID: {Id}", typeof(T).Name, id);
return false;
}
}
public virtual IQueryable<T> Get()
{
logger.LogDebug("Получаю набор объектов типа {EntityType}", typeof(T).Name);
_logger.LogDebug("Получаю набор объектов типа {EntityType}", typeof(T).Name);
return EntitySet;
}
public virtual async Task<T?> GetAsync(Guid id)
{
logger.LogDebug("Получаю объект типа {EntityType} по ID: {Id}", typeof(T).Name, id);
_logger.LogDebug("Получаю объект типа {EntityType} по ID: {Id}", typeof(T).Name, id);
return await EntitySet.FirstOrDefaultAsync(t => t.Id == id);
}
public virtual IQueryable<T> GetPage(IQueryable<T> query, PaginationFilter paginationFilter)
{
logger.LogDebug("Получаю страницу объектов типа {EntityType}, страница: {PageNumber}, размер: {PageSize}",
_logger.LogDebug("Получаю страницу объектов типа {EntityType}, страница: {PageNumber}, размер: {PageSize}",
typeof(T).Name, paginationFilter.PageNumber, paginationFilter.PageSize);
int skip = (paginationFilter.PageNumber - 1) * paginationFilter.PageSize;

View File

@@ -1,9 +1,11 @@
using Microsoft.EntityFrameworkCore;
using InfluxDB.Client.Api.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.Core.Repositories.Interfaces;
using PARR.DAL.Context;
using PARR.DAL.Repositories.Base;
using PARR.Domain.Entities;
using PARR.Domain.Entities.RobotEntities;
using PARR.Domain.Enums;
using PARR.Domain.Settings;
@@ -52,7 +54,7 @@ namespace PARR.DAL.Repositories
? ((TaskStatusEnum)taskStatusValue).ToString()
: $"Unknown ({taskStatusValue})";
logger.LogInformation("Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как текущий статус {currentStatus}",
_logger.LogInformation("Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как текущий статус {currentStatus}",
updatingStatus, configuration.Id, configuration.TemplateId, taskStatusName);
return false;
}
@@ -63,13 +65,13 @@ namespace PARR.DAL.Repositories
// есть ли связь у config с templetes, может инклуда нет, мало ли
if (configuration.Template == null)
{
logger.LogWarning("При изменении статуса задания на обновление шаблона, не смог проверить наличае ScheduleEsppId, так как нет Include с Templates. Пропустил эту проверку. configurationId: {configurationId}", configuration.Id);
_logger.LogWarning("При изменении статуса задания на обновление шаблона, не смог проверить наличае ScheduleEsppId, так как нет Include с Templates. Пропустил эту проверку. configurationId: {configurationId}", configuration.Id);
}
else
{
if (configuration.Template.ScheduleEsppId == null)
{
logger.LogInformation("Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как у шаблона отсутсвтует ScheduleEsppId=null",
_logger.LogInformation("Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как у шаблона отсутсвтует ScheduleEsppId=null",
updatingStatus, configuration.Id, configuration.TemplateId);
return false;
}
@@ -78,7 +80,7 @@ namespace PARR.DAL.Repositories
// Статус ОК, можно ставить Updating
ChangeTaskStatus(updatingStatus, configuration);
logger.LogInformation("Установлен статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}", updatingStatus, configuration.Id, configuration.TemplateId);
_logger.LogInformation("Установлен статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}", updatingStatus, configuration.Id, configuration.TemplateId);
return true;
}
@@ -94,8 +96,8 @@ namespace PARR.DAL.Repositories
configuration.AttemptsNumber++;
configuration.LastRobotStatusUpdated = DateTimeOffset.UtcNow;
break;
//case RobotStatusEnum.Error:
// break;
case RobotStatusEnum.Error:
break;
case RobotStatusEnum.Complete:
configuration.LastRobotStatusUpdated = DateTimeOffset.UtcNow;
break;
@@ -108,6 +110,14 @@ namespace PARR.DAL.Repositories
}
}
public void SetErrorRobotStatusAndMaxAttempts(RobotConfiguration configuration)
{
ChangeRobotStatus(RobotStatusEnum.Error, configuration);
configuration.AttemptsNumber = settingsFromDb.RobotAttemptsNumber;
configuration.LastRobotStatusUpdated = DateTimeOffset.UtcNow;
}
public async Task<bool> SetInProgressStatusAsync(Guid id)
{
@@ -144,7 +154,7 @@ namespace PARR.DAL.Repositories
if (config == null)
{
logger.LogError($"У шаблона нет конфигурации роботов. TemplateId: {template.Id}");
_logger.LogError($"У шаблона нет конфигурации роботов. TemplateId: {template.Id}");
throw new Exception($"У шаблона нет конфигурации роботов. TemplateId: {template.Id}");
}
@@ -160,25 +170,82 @@ namespace PARR.DAL.Repositories
var endDate = DateTimeOffset.UtcNow.Add(-robotWaitTime);
var configObjs = await EntitySet.Where(t =>
var expiredConfigs = await EntitySet.Where(t =>
t.RobotStatusCode == (int)RobotStatusEnum.InProgress
&& t.AttemptsNumber >= robotAttemptsNumber
&& t.LastRobotStatusUpdated <= endDate
).ToListAsync();
if (!configObjs.Any())
if (!expiredConfigs.Any())
return;
configObjs.ForEach(item =>
foreach (var item in expiredConfigs)
{
ChangeRobotStatus(RobotStatusEnum.Error, item);
logger.LogInformation($"Устанавливаю RobotStatus: {RobotStatusEnum.Error} для RobotConfigurationId {item.Id}");
});
_logger.LogInformation("Устанавливаю статус RobotStatus: {RobotStatus} для RobotConfigurationId: {RobotConfigurationId}", RobotStatusEnum.Error, item.Id);
}
#region Ищем, есть ли связанные шаблоны, которые должны переименоваться, им тоже нужно установить статус ошибки, но только для Шаблонов
// Проактивная обработка связанных шаблонов переименования Old->New
// Если старый шаблон умен, мы должны сразу убить (!!!замочить!!!) и новый (целевой), чтобы он не висел вечно в ожидании.
var expiredTemplateIds = expiredConfigs
.Where(t => t.RobotCode == (int)RobotsEnum.TemplateOrder)
.Select(t => t.TemplateId)
.Distinct()
.ToList();
if (expiredTemplateIds.Any())
{
// Находим OldName для этих шаблонов из таблицы переименований.
var oldNamesToFail = await EntityContext.Templates
.Where(t => expiredTemplateIds.Contains(t.Id) && t.TemplateRenamePending != null)
.Select(t => t.TemplateRenamePending!.OldName)
.Distinct()
.ToListAsync();
// Находим целевые (новые задачи), имена которых совпадают с найденными OldName
if (oldNamesToFail.Any())
{
var targetConfigs = await EntitySet
.Where(t =>
t.RobotCode == (int)RobotsEnum.TemplateOrder
&& t.RobotStatusCode != (int)RobotStatusEnum.Error // Не трогаем те, что уже в ошибке
&& oldNamesToFail.Contains(t.Template!.Name)
).ToListAsync();
foreach (var item in targetConfigs)
{
SetErrorRobotStatusAndMaxAttempts(item);
// Пишем в лог роботу
var history = new RobotHistory
{
Id = Guid.NewGuid(),
HistoryLevel = (int)RobotStatusEnum.Error,
TaskStatusCode = item.TaskStatusCode,
RobotConfigurationId = item.Id,
RobotIp = null,
RobotId = ParrComponentsEnum.Api.ToString(),
RobotMessage = "[RobotConfigurationRepository] Установлен статус ошибки, так как не переименован связанный шаблон"
};
// Синхронный Add работает быстрее и безопаснее внутри цикла
EntityContext.RobotHistories.Add(history);
_logger.LogInformation("Проактивно установлен статус {Status} для целевого задания RobotConfigurationID: {Id} из-за ошибки старого шаблона.", RobotStatusEnum.Error, item.Id);
}
}
}
#endregion
var result = await CommitAsync();
if (!result)
logger.LogError($"Ошибка при сохранении изменений RobotStatus для RobotConfigurationId: item.Id, RobotStatus: {RobotStatusEnum.Error}");
_logger.LogError("Ошибка при сохранении изменений RobotStatus для просроченных заданий. Откат транзакции.");
//else
// logger.LogInformation("Успешно обработано и переведено в статус Ошибки просроченных заданий: {Count} шт.", configObjs.Count + linksCount);
}

View File

@@ -0,0 +1,48 @@
using Microsoft.Extensions.Logging;
using PARR.Core.Repositories.Interfaces.TemplateRepositories;
using PARR.DAL.Context;
using PARR.Domain.Entities.TemplateEntities;
namespace PARR.DAL.Repositories.TemplateRepositories
{
internal class TemplateRenamePendingRepository : ITemplateRenamePendingRepository
{
private readonly DataContext _dataContext;
private readonly ILogger<TemplateRenamePendingRepository> _logger;
public TemplateRenamePendingRepository(
DataContext dataContext,
ILogger<TemplateRenamePendingRepository> logger
)
{
_dataContext = dataContext;
_logger = logger;
}
public IQueryable<TemplateRenamePending> Get()
{
return _dataContext.TemplateRenamePendings;
}
public void Remove(TemplateRenamePending obj)
{
_dataContext.TemplateRenamePendings.Remove(obj);
}
public async Task<bool> CreateAsync(TemplateRenamePending obj)
{
try
{
await _dataContext.TemplateRenamePendings.AddAsync(obj);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка при добавлении объекта типа TemplateRenamePending в БД");
return false;
}
}
}
}

View File

@@ -16,7 +16,7 @@ namespace PARR.DAL.Repositories
public async Task<Template?> GetTemplateByNameAsync(string name)
{
logger.LogDebug("Поиск шаблона по имени: {TemplateName}", name);
_logger.LogDebug("Поиск шаблона по имени: {TemplateName}", name);
var template = await GetWithIncludes()
.Include(t => t.RobotConfigurations)
@@ -24,11 +24,11 @@ namespace PARR.DAL.Repositories
if (template != null)
{
logger.LogDebug("Шаблон найден: {TemplateId}, имя: {TemplateName}", template.Id, template.Name);
_logger.LogDebug("Шаблон найден: {TemplateId}, имя: {TemplateName}", template.Id, template.Name);
}
else
{
logger.LogDebug("Шаблон с именем {TemplateName} не найден", name);
_logger.LogDebug("Шаблон с именем {TemplateName} не найден", name);
}
return template;
@@ -36,7 +36,7 @@ namespace PARR.DAL.Repositories
public IQueryable<Template> GetWithIncludes()
{
logger.LogDebug("Получаю шаблоны с include связями");
_logger.LogDebug("Получаю шаблоны с include связями");
return Get()
.Include(h => h.Unit)
@@ -60,7 +60,7 @@ namespace PARR.DAL.Repositories
public override Task<bool> CreateAsync(Template obj)
{
logger.LogDebug("Создание шаблона: {TemplateName}", obj.Name);
_logger.LogDebug("Создание шаблона: {TemplateName}", obj.Name);
// добавление роботов для шаблона
obj.RobotConfigurations = new List<RobotConfiguration>
@@ -92,7 +92,7 @@ namespace PARR.DAL.Repositories
};
logger.LogDebug("Добавлены роботы для шаблона {TemplateName}", obj.Name);
_logger.LogDebug("Добавлены роботы для шаблона {TemplateName}", obj.Name);
return base.CreateAsync(obj);
}
@@ -100,7 +100,7 @@ namespace PARR.DAL.Repositories
public async Task<Guid?> ReserveUnusedTemplateAsync(Guid newUnitId, HistoryInitiator initiator)
{
logger.LogDebug("Резервирую неиспользуемый шаблон для UnitId: {UnitId}", newUnitId);
_logger.LogDebug("Резервирую неиспользуемый шаблон для UnitId: {UnitId}", newUnitId);
// Явная транзакция гарантирует атомарность UPDATE + подзапроса
await using var transaction = await EntityContext.Database.BeginTransactionAsync();
@@ -167,18 +167,18 @@ namespace PARR.DAL.Repositories
if (reservedTemplateId != Guid.Empty)
{
logger.LogInformation("Успешно зарезервирован шаблон с ID: {TemplateId} для UnitId: {UnitId}",
_logger.LogInformation("Успешно зарезервирован шаблон с ID: {TemplateId} для UnitId: {UnitId}",
reservedTemplateId, newUnitId);
return reservedTemplateId;
}
logger.LogDebug("Не удалось зарезервировать шаблон для UnitId: {UnitId}", newUnitId);
_logger.LogDebug("Не удалось зарезервировать шаблон для UnitId: {UnitId}", newUnitId);
return null;
}
catch (Exception ex)
{
await transaction.RollbackAsync();
logger.LogError(ex, "Ошибка при резервировании шаблона для UnitId: {UnitId}", newUnitId);
_logger.LogError(ex, "Ошибка при резервировании шаблона для UnitId: {UnitId}", newUnitId);
throw;
}
}

View File

@@ -84,7 +84,7 @@ namespace PARR.DAL.Repositories
var exist = await GetAsync(id);
if (exist == null)
{
logger.LogError($"Ошибка при удалении из БД. Не найдена запись в БД с id: {id}");
_logger.LogError($"Ошибка при удалении из БД. Не найдена запись в БД с id: {id}");
return false;
}