feat(aihitMainSyncer): реализована логика синхронизации таблиц unit.* с данными из АИХ ИТ

This commit is contained in:
Mikhail Kuznetsov
2025-05-21 11:53:07 +10:00
parent 1ce8fcb284
commit 0fd0b4881f
13 changed files with 177 additions and 78 deletions

View File

@@ -58,7 +58,10 @@ namespace PARR.AIHITMainLoader
{ {
loaderSettings.ResponseAreas.ForEach(responseArea => loaderSettings.ResponseAreas.ForEach(responseArea =>
{ {
logger.LogDebug($"responseArea = {responseArea}");
var EKs = service.Invoke(responseArea); var EKs = service.Invoke(responseArea);
if (EKs != null && EKs.Any())
EKs.ToList().ForEach(item => EKs.ToList().ForEach(item =>
{ {
listToMq.Add(item.ToMainData()); listToMq.Add(item.ToMainData());
@@ -88,9 +91,9 @@ namespace PARR.AIHITMainLoader
} }
private List<Func<string, IEnumerable<IMainData>>> GetServices() private List<Func<string, IEnumerable<IMainData>?>> GetServices()
{ {
var serviceList = new List<Func<string, IEnumerable<IMainData>>>(); var serviceList = new List<Func<string, IEnumerable<IMainData>?>>();
serviceList.Add(aihitService.GetCvkData); serviceList.Add(aihitService.GetCvkData);
serviceList.Add(aihitService.GetPtkData); serviceList.Add(aihitService.GetPtkData);

View File

@@ -21,7 +21,7 @@ namespace PARR.AIHITMainLoader.Services
} }
public IEnumerable<IMainData> GetPtkData(string respArea) public IEnumerable<IMainData>? GetPtkData(string respArea)
{ {
var parameters = new List<SqlParameter>() { new SqlParameter("@зо", respArea) }; var parameters = new List<SqlParameter>() { new SqlParameter("@зо", respArea) };
@@ -45,7 +45,7 @@ namespace PARR.AIHITMainLoader.Services
} }
public IEnumerable<IMainData> GetCvkData(string respArea) public IEnumerable<IMainData>? GetCvkData(string respArea)
{ {
var parameters = new List<SqlParameter>() { new SqlParameter("@зо", respArea) }; var parameters = new List<SqlParameter>() { new SqlParameter("@зо", respArea) };

View File

@@ -4,7 +4,7 @@ namespace PARR.AIHITMainLoader.Services
{ {
internal interface IAihitService internal interface IAihitService
{ {
IEnumerable<IMainData> GetPtkData(string respArea); IEnumerable<IMainData>? GetPtkData(string respArea);
IEnumerable<IMainData> GetCvkData(string respArea); IEnumerable<IMainData>? GetCvkData(string respArea);
} }
} }

View File

@@ -13,18 +13,21 @@ namespace PARR.AIHITMainSyncer.Services
private readonly ITransformService transformService; private readonly ITransformService transformService;
private readonly IUnitService unitService; private readonly IUnitService unitService;
private readonly IUnitFieldService unitFieldService; private readonly IUnitFieldService unitFieldService;
private readonly IUnitFieldValueService unitFieldValueService;
public SyncerService( public SyncerService(
ILogger<SyncerService> logger, ILogger<SyncerService> logger,
ITransformService transformService, ITransformService transformService,
IUnitService unitService, IUnitService unitService,
IUnitFieldService unitFieldService IUnitFieldService unitFieldService,
IUnitFieldValueService unitFieldValueService
) )
{ {
this.logger = logger; this.logger = logger;
this.transformService = transformService; this.transformService = transformService;
this.unitService = unitService; this.unitService = unitService;
this.unitFieldService = unitFieldService; this.unitFieldService = unitFieldService;
this.unitFieldValueService = unitFieldValueService;
} }
@@ -41,64 +44,88 @@ namespace PARR.AIHITMainSyncer.Services
private async Task SyncUnitAsync(AihitMainDataMq objFromQuery) private async Task SyncUnitAsync(AihitMainDataMq objFromQuery)
{ {
var fields = await GetFieldsInObjectAsync(objFromQuery); var isChanged = false;
var unit = await unitService.GetUnitWithFieldsAsync(objFromQuery.Name); var unit = await unitService.GetUnitByName(objFromQuery.Name);
foreach (var item in objFromQuery.Properties)
{ //актуализируем справочники в соответствии с пришедшими данными
var field = await CreateUnitFieldIfNotExistAsync(item.Key);
var value = await CreateFieldValueIfNotExistAsync(field, item.Value);
//Если ЭК не найден то создаём его
if (unit == null) if (unit == null)
unit = await CreateUnitAsync(objFromQuery); unit = await CreateUnitAsync(objFromQuery);
//else
// logger.LogDebug($"Найден Unit в БД: {unit.Name})");
//теперь проверяем наличие поля связанного с этим ЭК
if (SyncFields(unit, field) && !isChanged)
isChanged = true;
//Синхронизируем значение
if (SyncValues(unit, field, value) && !isChanged)
isChanged = true;
}
if (isChanged && !await unitService.CommitAsync())
logger.LogError($"Не удалось изменить Unit {objFromQuery.Name}");
else else
logger.LogDebug($"Найден Unit в БД: {unit.Name})"); logger.LogInformation($"----- Набор данных в Unit изменён: {objFromQuery.Name} -----");
await SyncFieldInUnitAsync(unit!, fields);
} }
private async Task SyncFieldInUnitAsync(Unit unit, List<Guid> fieldsId) private bool SyncFields(Unit unit, UnitField field)
{ {
var isChanged = false; var isChanged = false;
//Смотрим какие поля нам прислали, есть новые? var fieldInUnit = unit!.UnitFields.FirstOrDefault(u => u.FieldId == field.Id);
var newFields = fieldsId.Except(unit.UnitFields.Select(uf => uf.FieldId)).ToList();
//добавляем если есть if (fieldInUnit == null)
if (newFields.Any())
{
if (!isChanged)
isChanged = true;
newFields.ForEach(uf =>
{ {
if (!isChanged) isChanged = true;
unit.UnitFields.Add( unit.UnitFields.Add(
new UnitInField { UnitId = unit.Id, FieldId = uf, DateCreated = DateTimeOffset.UtcNow } new UnitInField { UnitId = unit.Id, FieldId = field.Id, DateCreated = DateTimeOffset.UtcNow }
); );
});
} }
//TODO: Удаление неактуальных return isChanged;
if (isChanged && !await unitFieldService.CommitAsync())
logger.LogError($"Не удалось изменить набор Fields в Unit {unit.Name}");
else
logger.LogInformation($"----- Набор Fields в Unit изменён: {unit.Name} -----");
} }
private async Task<List<Guid>> GetFieldsInObjectAsync(AihitMainDataMq objFromQuery)
private bool SyncValues(Unit unit, UnitField field, UnitFieldValue value)
{ {
var fields = new List<Guid>(); var isChanged = false;
foreach (var item in objFromQuery.Properties) var valueInUnit = unit!.UnitValues.FirstOrDefault(uv => uv.FieldId == field.Id);
if (valueInUnit == null)
{ {
var field = await CreateUnitFieldIfNotExistAsync(item.Key); if (!isChanged) isChanged = true;
fields.Add(field!.Id); unit.UnitValues.Add(
new UnitInValue
{
UnitId = unit.Id,
FieldId = field.Id,
ValueId = value.Id,
DateCreated = DateTime.UtcNow
}
);
}
else if (valueInUnit.Value != value)
{
if (!isChanged) isChanged = true;
{
valueInUnit.ValueId = value.Id;
valueInUnit.DateModified = DateTime.UtcNow;
}
} }
return fields; return isChanged;
} }
private async Task<Unit?> CreateUnitAsync(AihitMainDataMq objFromQuery) private async Task<Unit> CreateUnitAsync(AihitMainDataMq objFromQuery)
{ {
var unit = new Unit { Name = objFromQuery.Name.Trim() }; var unit = new Unit { Name = objFromQuery.Name.Trim() };
@@ -107,11 +134,11 @@ namespace PARR.AIHITMainSyncer.Services
else else
logger.LogInformation($"----- Создан Unit: {unit.Name} -----"); logger.LogInformation($"----- Создан Unit: {unit.Name} -----");
return await unitService.GetUnitWithFieldsAsync(unit.Name); return (await unitService.GetUnitByName(unit.Name))!;
} }
private async Task<UnitField?> CreateUnitFieldIfNotExistAsync(string name) private async Task<UnitField> CreateUnitFieldIfNotExistAsync(string name)
{ {
var existUnitField = await unitFieldService.GetByAihitNameAsync(name); var existUnitField = await unitFieldService.GetByAihitNameAsync(name);
@@ -122,7 +149,7 @@ namespace PARR.AIHITMainSyncer.Services
{ {
Id = Guid.NewGuid(), Id = Guid.NewGuid(),
AihitName = name.Trim(), AihitName = name.Trim(),
EsppName = null EsppName = null,
}; };
if (!await unitFieldService.CreateAsync(field) || !await unitFieldService.CommitAsync()) if (!await unitFieldService.CreateAsync(field) || !await unitFieldService.CommitAsync())
@@ -130,7 +157,61 @@ namespace PARR.AIHITMainSyncer.Services
else else
logger.LogInformation($"Создана запись а таблице Fields: {name}, {field.ToJson()}"); logger.LogInformation($"Создана запись а таблице Fields: {name}, {field.ToJson()}");
return await unitFieldService.GetAsync(field.Id); return (await unitFieldService.GetAsync(field.Id))!;
}
private async Task<UnitFieldValue> CreateFieldValueIfNotExistAsync(UnitField field, string? value)
{
var existUnitFieldValue = await unitFieldValueService.GetByValueNameAsync(value);
//если значение существует отдаем его
if (existUnitFieldValue != null)
{
//проверяем связь с таблицей Fields
if (existUnitFieldValue.FieldValues.FirstOrDefault(fv => fv.FieldId == field.Id) == null)
{
var unitFieldInUnitFieldValue = new UnitFieldInUnitFieldValue
{
FieldId = field.Id,
FieldValueId = existUnitFieldValue.Id,
DateCreated = DateTime.UtcNow,
};
existUnitFieldValue.FieldValues.Add(unitFieldInUnitFieldValue);
if (!await unitFieldValueService.CommitAsync())
logger.LogError($"Не удалось создать связь таблицы FieldValues и Fields: {unitFieldValueService.ToJson()}");
else
logger.LogInformation($"Создана связь таблицы FieldValues и Fields: {unitFieldValueService.ToJson()}");
}
return existUnitFieldValue;
}
//значение не найдено значит создаём его
var newValue = new UnitFieldValue
{
Id = Guid.NewGuid(),
Value = (value == null) ? null : value.Trim()
};
//и привязываем значение к полю
newValue.FieldValues.Add(
new UnitFieldInUnitFieldValue
{
FieldId = field.Id,
FieldValueId = newValue.Id,
DateCreated = DateTime.UtcNow,
}
);
//пишем в базу данных
if (!await unitFieldValueService.CreateAsync(newValue) || !await unitFieldValueService.CommitAsync())
logger.LogError($"Не удалось создать запись в таблице Values: {newValue.Value}, {newValue.ToJson()}");
else
logger.LogInformation($"Создана запись а таблице Values: {newValue.Value}, {newValue.ToJson()}");
return (await unitFieldValueService.GetAsync(newValue.Id))!;
} }
} }
} }

View File

@@ -12,8 +12,8 @@ using PARR.DAL.Context;
namespace PARR.DAL.Migrations namespace PARR.DAL.Migrations
{ {
[DbContext(typeof(DataContext))] [DbContext(typeof(DataContext))]
[Migration("20250514051030_units")] [Migration("20250520021852_tblUnits")]
partial class units partial class tblUnits
{ {
/// <inheritdoc /> /// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
@@ -2667,14 +2667,14 @@ namespace PARR.DAL.Migrations
b.Property<DateTimeOffset?>("DateModified") b.Property<DateTimeOffset?>("DateModified")
.HasColumnType("timestamp with time zone"); .HasColumnType("timestamp with time zone");
b.Property<Guid>("VlaueId") b.Property<Guid>("ValueId")
.HasColumnType("uuid"); .HasColumnType("uuid");
b.HasKey("UnitId", "FieldId"); b.HasKey("UnitId", "FieldId");
b.HasIndex("FieldId"); b.HasIndex("FieldId");
b.HasIndex("VlaueId"); b.HasIndex("ValueId");
b.ToTable("UnitInValues", "unit", t => b.ToTable("UnitInValues", "unit", t =>
{ {
@@ -3224,14 +3224,14 @@ namespace PARR.DAL.Migrations
.IsRequired(); .IsRequired();
b.HasOne("PARR.DAL.Models.Unit.Unit", "Unit") b.HasOne("PARR.DAL.Models.Unit.Unit", "Unit")
.WithMany("UnitInValues") .WithMany("UnitValues")
.HasForeignKey("UnitId") .HasForeignKey("UnitId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired();
b.HasOne("PARR.DAL.Models.Unit.UnitFieldValue", "Value") b.HasOne("PARR.DAL.Models.Unit.UnitFieldValue", "Value")
.WithMany("UnitInValues") .WithMany("UnitInValues")
.HasForeignKey("VlaueId") .HasForeignKey("ValueId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired();
@@ -3445,7 +3445,7 @@ namespace PARR.DAL.Migrations
{ {
b.Navigation("UnitFields"); b.Navigation("UnitFields");
b.Navigation("UnitInValues"); b.Navigation("UnitValues");
}); });
modelBuilder.Entity("PARR.DAL.Models.Unit.UnitField", b => modelBuilder.Entity("PARR.DAL.Models.Unit.UnitField", b =>

View File

@@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
namespace PARR.DAL.Migrations namespace PARR.DAL.Migrations
{ {
/// <inheritdoc /> /// <inheritdoc />
public partial class units : Migration public partial class tblUnits : Migration
{ {
/// <inheritdoc /> /// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
@@ -127,7 +127,7 @@ namespace PARR.DAL.Migrations
{ {
UnitId = table.Column<Guid>(type: "uuid", nullable: false), UnitId = table.Column<Guid>(type: "uuid", nullable: false),
FieldId = table.Column<Guid>(type: "uuid", nullable: false), FieldId = table.Column<Guid>(type: "uuid", nullable: false),
VlaueId = table.Column<Guid>(type: "uuid", nullable: false), ValueId = table.Column<Guid>(type: "uuid", nullable: false),
DateCreated = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false), DateCreated = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
DateModified = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true) DateModified = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true)
}, },
@@ -135,8 +135,8 @@ namespace PARR.DAL.Migrations
{ {
table.PrimaryKey("PK_UnitInValues", x => new { x.UnitId, x.FieldId }); table.PrimaryKey("PK_UnitInValues", x => new { x.UnitId, x.FieldId });
table.ForeignKey( table.ForeignKey(
name: "FK_UnitInValues_FieldValues_VlaueId", name: "FK_UnitInValues_FieldValues_ValueId",
column: x => x.VlaueId, column: x => x.ValueId,
principalSchema: "unit", principalSchema: "unit",
principalTable: "FieldValues", principalTable: "FieldValues",
principalColumn: "Id", principalColumn: "Id",
@@ -195,10 +195,10 @@ namespace PARR.DAL.Migrations
column: "FieldId"); column: "FieldId");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_UnitInValues_VlaueId", name: "IX_UnitInValues_ValueId",
schema: "unit", schema: "unit",
table: "UnitInValues", table: "UnitInValues",
column: "VlaueId"); column: "ValueId");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_Units_Name", name: "IX_Units_Name",

View File

@@ -2664,14 +2664,14 @@ namespace PARR.DAL.Migrations
b.Property<DateTimeOffset?>("DateModified") b.Property<DateTimeOffset?>("DateModified")
.HasColumnType("timestamp with time zone"); .HasColumnType("timestamp with time zone");
b.Property<Guid>("VlaueId") b.Property<Guid>("ValueId")
.HasColumnType("uuid"); .HasColumnType("uuid");
b.HasKey("UnitId", "FieldId"); b.HasKey("UnitId", "FieldId");
b.HasIndex("FieldId"); b.HasIndex("FieldId");
b.HasIndex("VlaueId"); b.HasIndex("ValueId");
b.ToTable("UnitInValues", "unit", t => b.ToTable("UnitInValues", "unit", t =>
{ {
@@ -3221,14 +3221,14 @@ namespace PARR.DAL.Migrations
.IsRequired(); .IsRequired();
b.HasOne("PARR.DAL.Models.Unit.Unit", "Unit") b.HasOne("PARR.DAL.Models.Unit.Unit", "Unit")
.WithMany("UnitInValues") .WithMany("UnitValues")
.HasForeignKey("UnitId") .HasForeignKey("UnitId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired();
b.HasOne("PARR.DAL.Models.Unit.UnitFieldValue", "Value") b.HasOne("PARR.DAL.Models.Unit.UnitFieldValue", "Value")
.WithMany("UnitInValues") .WithMany("UnitInValues")
.HasForeignKey("VlaueId") .HasForeignKey("ValueId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired();
@@ -3442,7 +3442,7 @@ namespace PARR.DAL.Migrations
{ {
b.Navigation("UnitFields"); b.Navigation("UnitFields");
b.Navigation("UnitInValues"); b.Navigation("UnitValues");
}); });
modelBuilder.Entity("PARR.DAL.Models.Unit.UnitField", b => modelBuilder.Entity("PARR.DAL.Models.Unit.UnitField", b =>

View File

@@ -30,6 +30,6 @@ namespace PARR.DAL.Models.Unit
public ICollection<UnitInField> UnitFields { get; set; } = new HashSet<UnitInField>(); public ICollection<UnitInField> UnitFields { get; set; } = new HashSet<UnitInField>();
public ICollection<UnitInValue> UnitInValues { get; set; } = new HashSet<UnitInValue>(); public ICollection<UnitInValue> UnitValues { get; set; } = new HashSet<UnitInValue>();
} }
} }

View File

@@ -15,7 +15,7 @@ namespace PARR.DAL.Models.Unit
public Guid FieldId { get; set; } public Guid FieldId { get; set; }
public Guid VlaueId { get; set; } public Guid ValueId { get; set; }
public DateTimeOffset DateCreated { get; set; } public DateTimeOffset DateCreated { get; set; }
@@ -28,7 +28,7 @@ namespace PARR.DAL.Models.Unit
[ForeignKey(nameof(FieldId))] [ForeignKey(nameof(FieldId))]
public UnitField? Field { get; set; } public UnitField? Field { get; set; }
[ForeignKey(nameof(VlaueId))] [ForeignKey(nameof(ValueId))]
public UnitFieldValue? Value { get; set; } public UnitFieldValue? Value { get; set; }
} }
} }

View File

@@ -19,5 +19,17 @@ namespace PARR.DAL.Services.Implementations.Unit
{ {
this.dataContext = dataContext; this.dataContext = dataContext;
} }
public async Task<UnitFieldValue?> GetByValueNameAsync(string? value)
{
var query = EntitySet
.Include(v => v.FieldValues);
if (string.IsNullOrWhiteSpace(value))
return await query.FirstOrDefaultAsync(uf => uf.Value == null);
return await query.FirstOrDefaultAsync(uf => uf.Value!.ToLower() == value.ToLower());
}
} }
} }

View File

@@ -20,18 +20,20 @@ namespace PARR.DAL.Services.Implementations.Unit
} }
public async Task<Models.Unit.Unit?> GetUnitWithFieldsAsync(string name) public async Task<Models.Unit.Unit?> GetUnitByName(string name)
{ {
return await GetUnitWithIncludeFields() return await GetUnitWithFieldsAndValues()
.FirstOrDefaultAsync(u => u.Name.ToLower() == name.ToLower()); .FirstOrDefaultAsync(u => u.Name.ToLower() == name.ToLower());
} }
private IQueryable<Models.Unit.Unit> GetUnitWithIncludeFields() private IQueryable<Models.Unit.Unit> GetUnitWithFieldsAndValues()
{ {
return EntitySet return EntitySet
.Include(t => t.UnitFields) .Include(u => u.UnitFields)
.ThenInclude(f => f.UnitField); .ThenInclude(f => f.UnitField)
.Include(u => u.UnitValues)
.ThenInclude(v => v.Value);
} }
} }
} }

View File

@@ -3,7 +3,8 @@ using PARR.DAL.Services.Interfaces.Base;
namespace PARR.DAL.Services.Interfaces.Unit namespace PARR.DAL.Services.Interfaces.Unit
{ {
internal interface IUnitFieldValueService: IBaseService<UnitFieldValue> public interface IUnitFieldValueService: IBaseService<UnitFieldValue>
{ {
Task<UnitFieldValue?> GetByValueNameAsync(string? value);
} }
} }

View File

@@ -4,6 +4,6 @@ namespace PARR.DAL.Services.Interfaces.Unit
{ {
public interface IUnitService : IBaseService<Models.Unit.Unit> public interface IUnitService : IBaseService<Models.Unit.Unit>
{ {
Task<Models.Unit.Unit?> GetUnitWithFieldsAsync(string name); Task<Models.Unit.Unit?> GetUnitByName(string name);
} }
} }