feat(aihit): В Loader добавлена процедура mao2.dbo.sp_IPP_PARR_PTK_get_EK_REG для загрузки данных по региональным ЭК

This commit is contained in:
Mikhail Kuznetsov
2025-11-18 17:56:12 +10:00
parent c3c6ab787e
commit 629a487875
6 changed files with 212 additions and 51 deletions

View File

@@ -5,29 +5,22 @@ namespace PARR.AIHITLoaderWorker
public class Worker : BackgroundService public class Worker : BackgroundService
{ {
private readonly ILogger<Worker> _logger; private readonly ILogger<Worker> _logger;
private readonly IServiceProvider serviceProvider; private readonly IAihitMainLoader aihitMainLoader;
public Worker( public Worker(
ILogger<Worker> logger, ILogger<Worker> logger,
IServiceProvider serviceProvider IAihitMainLoader aihitMainLoader
) )
{ {
_logger = logger; _logger = logger;
this.serviceProvider = serviceProvider; this.aihitMainLoader = aihitMainLoader;
} }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{ {
using (var scope = serviceProvider.CreateScope()) await aihitMainLoader.StartAsync();
{ await Task.Delay(Timeout.Infinite, stoppingToken);
var aihitLoader = scope.ServiceProvider.GetService<IAihitMainLoader>();
if (aihitLoader == null)
throw new Exception("<22><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> IAihitMainLoader, scope.ServiceProvider.GetService<IAihitMainLoader>()");
await aihitLoader.StartAsync();
}
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PARR.AIHITMainLoader.Models; using PARR.AIHITMainLoader.Models;
using PARR.AIHITMainLoader.Services; using PARR.AIHITMainLoader.Services;
using PARR.AIHITMainLoader.Settings; using PARR.AIHITMainLoader.Settings;
@@ -15,8 +16,8 @@ namespace PARR.AIHITMainLoader
private readonly WorkerSettings workerSettings; private readonly WorkerSettings workerSettings;
private readonly LoaderSettings loaderSettings; private readonly LoaderSettings loaderSettings;
private readonly MqSettings mqSettings; private readonly MqSettings mqSettings;
private readonly IAihitService aihitService;
private readonly IMqService mqService; private readonly IMqService mqService;
private readonly IServiceProvider serviceProvider;
public AihitMainLoader( public AihitMainLoader(
ILogger<AihitMainLoader> logger, ILogger<AihitMainLoader> logger,
@@ -24,8 +25,8 @@ namespace PARR.AIHITMainLoader
WorkerSettings workerSettings, WorkerSettings workerSettings,
LoaderSettings loaderSettings, LoaderSettings loaderSettings,
MqSettings mqSettings, MqSettings mqSettings,
IAihitService aihitService, IMqService mqService,
IMqService mqService IServiceProvider serviceProvider
) )
{ {
this.logger = logger; this.logger = logger;
@@ -33,8 +34,8 @@ namespace PARR.AIHITMainLoader
this.workerSettings = workerSettings; this.workerSettings = workerSettings;
this.loaderSettings = loaderSettings; this.loaderSettings = loaderSettings;
this.mqSettings = mqSettings; this.mqSettings = mqSettings;
this.aihitService = aihitService;
this.mqService = mqService; this.mqService = mqService;
this.serviceProvider = serviceProvider;
} }
@@ -48,55 +49,77 @@ namespace PARR.AIHITMainLoader
private async Task LoadDataAsync() private async Task LoadDataAsync()
{ {
logger.LogInformation("Запуск загрузки данных из АИХ ИТ."); try
var services = GetServices();
var listToMq = new List<AihitMainDataMq>();
services.ForEach(service =>
{ {
loaderSettings.ResponseAreas.ForEach(responseArea => logger.LogInformation("Запуск загрузки данных из АИХ ИТ.");
using (var scope = serviceProvider.CreateScope())
{ {
logger.LogDebug($"responseArea = {responseArea}"); var aihitService = scope.ServiceProvider.GetService<IAihitService>();
var EKs = service.Invoke(responseArea); if (aihitService == null)
throw new Exception($"Не найден сервис: {nameof(IAihitService)}");
if (EKs != null && EKs.Any()) var services = GetServices(aihitService);
EKs.ToList().ForEach(item =>
var listToMq = new List<AihitMainDataMq>();
foreach (var service in services)
{
foreach (var responseArea in loaderSettings.ResponseAreas)
{ {
listToMq.Add(item.ToMainData()); logger.LogDebug($"responseArea = {responseArea}");
}); var EKs = service.Invoke(responseArea);
});
});
var preparedData = listToMq.Select(d => JsonSerializer.Serialize(d)); if (EKs?.Any() == true)
{
foreach (var item in EKs)
{
if (item != null)
{
var mainData = item.ToMainData();
if (mainData != null)
listToMq.Add(mainData);
}
}
}
}
}
var parts = listToMq.Count() / loaderSettings.PackageSize; var preparedDataList = listToMq.Select(d => JsonSerializer.Serialize(d)).ToList();
parts++;
for (var i = 0; i < parts; i++) int count = preparedDataList.Count;
{ int packageSize = loaderSettings.PackageSize;
var batch = preparedData.Skip(i * loaderSettings.PackageSize).Take(loaderSettings.PackageSize).ToList(); var parts = count == 0 ? 0 : (count + packageSize - 1) / packageSize;
var sendResult = await mqService.SendAsync(mqSettings, batch.ToArray());
if (sendResult.IsSuccess) for (var i = 0; i < (count + packageSize - 1) / packageSize; i++)
{ {
logger.LogInformation($"Данные переданы в RabbitMQ: {batch.Count()}"); int start = i * packageSize;
logger.LogDebug($"Список ЭК переданных в RabbitMQ: {string.Join(", ", batch)}"); int length = Math.Min(packageSize, count - start);
var batch = preparedDataList.GetRange(start, length).ToArray();
var sendResult = await mqService.SendAsync(mqSettings, batch.ToArray());
if (sendResult.IsSuccess)
{
logger.LogInformation($"Данные переданы в RabbitMQ: {batch.Count()}");
logger.LogDebug($"Отправлено сообщений: {batch.Count()}, пример первого: {batch.FirstOrDefault()?.Substring(0, Math.Min(200, batch.FirstOrDefault()?.Length ?? 0))}...");
}
else
logger.LogError($"Ошибка при передаче данных в Rabbit, не переданные сообщения: {string.Join(", ", sendResult.NotSendMessages!)}");
}
} }
else } catch (Exception ex)
logger.LogError($"Ошибка при передаче данных в Rabbit, не переданные сообщения: {string.Join(", ", sendResult.NotSendMessages!)}"); {
logger.LogError(ex, "Ошибка при выполнении загрузки данных из АИХ ИТ.");
} }
// await Task.CompletedTask;
} }
private List<Func<string, IEnumerable<IMainData>?>> GetServices() private List<Func<string, IEnumerable<IMainData>?>> GetServices(IAihitService service)
{ {
var serviceList = new List<Func<string, IEnumerable<IMainData>?>>(); var serviceList = new List<Func<string, IEnumerable<IMainData>?>>();
serviceList.Add(aihitService.GetCvkData); serviceList.Add(service.GetCvkData);
serviceList.Add(aihitService.GetPtkData); serviceList.Add(service.GetPtkData);
serviceList.Add(service.GetRegionalEKData);
return serviceList; return serviceList;
} }

View File

@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using PARR.AIHITMainLoader.Models; using PARR.AIHITMainLoader.Models;
using PARR.BLL.Domain.Mq;
namespace PARR.AIHITMainLoader.Context namespace PARR.AIHITMainLoader.Context
{ {
@@ -10,5 +11,29 @@ namespace PARR.AIHITMainLoader.Context
public DbSet<CvkData> CvkDatas { get; set; } public DbSet<CvkData> CvkDatas { get; set; }
public DbSet<PtkData> PtkDatas { get; set; } public DbSet<PtkData> PtkDatas { get; set; }
public DbSet<PtkData> RegEKDatas { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//Делаем это чтобы EF не пытался трекать объкты полученые из хранимой процедуры
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<CvkData>(entity =>
{
entity.HasNoKey();
entity.ToView(null);
});
modelBuilder.Entity<PtkData>(entity =>
{
entity.HasNoKey();
entity.ToView(null);
});
modelBuilder.Entity<RegEKData>(entity =>
{
entity.HasNoKey();
entity.ToView(null);
});
}
} }
} }

View File

@@ -0,0 +1,94 @@
using PARR.BLL.Domain.Mq;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace PARR.AIHITMainLoader.Models
{
public class RegEKData : IMainData
{
[Column("ЗОНА_ОТВЕТСТВЕННОСТИ")]
public string? ResponseArea { get; set; }
[Column("КАТЕГОРИЯ_ЭК")]
public string? EKCategory { get; set; }
[Key]
[Column("КОД_ПОИСКАК")]
public string? EKFindCode { get; set; }
[Column("КРАТКОЕ_НАИМЕНОВАНИЕ")]
public string? ShortName { get; set; }
[Column("МВЗ")]
public string? MVZ { get; set; }
[Column("МОДЕЛЬ")]
public string? Model { get; set; }
[Column("ОТВЕТСТВЕННЫЙ_ЗАК")]
public string? ResponsibleByEK { get; set; }
[Column("ПОДКАТЕГОРИЯ_ЭК")]
public string? EKSubCategory { get; set; }
[Column("ПРОИЗВОДИТЕЛЬ_РАЗРАБОТЧИК")]
public string? Developer { get; set; }
[Column("РАБОЧАЯ_ГР_ОТВ_ЗАК")]
public string? WorkGroup { get; set; }
[Column("СТАТУС")]
public string? Status { get; set; }
[Column("ТИП_ЭК")]
public string? EKType { get; set; }
[Column("РГ_смены")]
public string? ShiftWorkGroup { get; set; }
[Column("Сервер СПД")]
public string? SPDServerType { get; set; }
[Column("Сервер БИР")]
public string? BIRServerType { get; set; }
[Column("АКТИВЕН")]
public int Active { get; set; }
[Column("НЕУНИКАЛЬНЫЙ_ЭК")]
public int IsNotUnique { get; set; }
[Column("ЗО_РГ")]
public string? WorkGroupResponseArea { get; set; }
public AihitMainDataMq ToMainData()
{
return new AihitMainDataMq
{
Name = EKFindCode!,//TODO Ты прям уверен???
Properties = new Dictionary<string, string?>
{
{"ЗОНА_ОТВЕТСТВЕННОСТИ", ResponseArea },
{"КАТЕГОРИЯ_ЭК", EKCategory },
{"КРАТКОЕ_НАИМЕНОВАНИЕ", ShortName },
{"MVZ", MVZ },
{"МОДЕЛЬ", Model },
{"ОТВЕТСТВЕННЫЙ_ЗАК", ResponsibleByEK },
{ОДКАТЕГОРИЯ_ЭК", EKSubCategory },
{РОИЗВОДИТЕЛЬ_РАЗРАБОТЧИК", Developer },
{"РАБОЧАЯ_ГР_ОТВ_ЗАК", WorkGroup },
{"СТАТУС", Status },
{"ТИП_ЭК", EKType },
{"РГ_смены", ShiftWorkGroup },
{"Сервер СПД", SPDServerType },
{"Сервер БИР", BIRServerType },
{"АКТИВЕН", Active.ToString() },
{"НЕУНИКАЛЬНЫЙ_ЭК", IsNotUnique.ToString() },
{"ЗО_РГ", WorkGroupResponseArea },
}
};
}
}
}

View File

@@ -67,5 +67,30 @@ namespace PARR.AIHITMainLoader.Services
return new List<IMainData>(); return new List<IMainData>();
} }
public IEnumerable<IMainData>? GetRegionalEKData(string respArea)
{
var parameters = new List<SqlParameter>() { new SqlParameter("@зо", respArea) };
try
{
var result = context.Set<RegEKData>().FromSqlRaw($"EXEC mao2.dbo.sp_IPP_PARR_PTK_get_EK_REG @зо", parameters.ToArray()).AsEnumerable();
if (result == null || !result.Any())
{
logger.LogWarning($"Процедура sp_IPP_PARR_PTK_get_EK_REG вернула пустой список ЭК");
}
return result;
}
catch (Exception ex)
{
logger.LogError(ex, $"Ошибка при выполнении ХП sp_IPP_PARR_PTK_get_EK_REG({respArea})");
}
return new List<IMainData>();
}
} }
} }

View File

@@ -6,5 +6,6 @@ namespace PARR.AIHITMainLoader.Services
{ {
IEnumerable<IMainData>? GetPtkData(string respArea); IEnumerable<IMainData>? GetPtkData(string respArea);
IEnumerable<IMainData>? GetCvkData(string respArea); IEnumerable<IMainData>? GetCvkData(string respArea);
IEnumerable<IMainData>? GetRegionalEKData(string respArea);
} }
} }