Внести исправления после ревью

This commit is contained in:
Roman Efremov 2024-11-28 08:55:50 +05:00
parent dc66522c0f
commit 1e87523ab9
15 changed files with 355 additions and 142 deletions

View File

@ -11,7 +11,7 @@ namespace Persistence.API.Controllers;
[ApiController] [ApiController]
[Authorize] [Authorize]
[Route("api/[controller]")] [Route("api/[controller]")]
public class TechMessagesController : ControllerBase, ITechMessages public class TechMessagesController : ControllerBase
{ {
private readonly ITechMessagesRepository techMessagesRepository; private readonly ITechMessagesRepository techMessagesRepository;
@ -41,8 +41,8 @@ public class TechMessagesController : ControllerBase, ITechMessages
/// <param name="autoDrillingSystem"></param> /// <param name="autoDrillingSystem"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
[HttpGet("statistics")] [HttpGet("statistics/{autoDrillingSystem}")]
public async Task<ActionResult<int>> GetStatistics(int importantId, string autoDrillingSystem, CancellationToken token) public async Task<ActionResult<int>> GetStatistics([FromRoute] string? autoDrillingSystem, int? importantId, CancellationToken token)
{ {
var result = await techMessagesRepository.GetStatistics(importantId, autoDrillingSystem, token); var result = await techMessagesRepository.GetStatistics(importantId, autoDrillingSystem, token);

View File

@ -1,9 +1,12 @@
using System.Reflection; using System.Reflection;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using Mapster;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Persistence.Database.Entity;
using Persistence.Models;
using Persistence.Models.Configurations; using Persistence.Models.Configurations;
using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerGen;
@ -11,6 +14,12 @@ namespace Persistence.API;
public static class DependencyInjection public static class DependencyInjection
{ {
public static void MapsterSetup()
{
TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<TechMessageDto, TechMessage>()
.Ignore(dest => dest.System, dest => dest.SystemId);
}
public static void AddSwagger(this IServiceCollection services, IConfiguration configuration) public static void AddSwagger(this IServiceCollection services, IConfiguration configuration)
{ {
services.AddSwaggerGen(c => services.AddSwaggerGen(c =>

View File

@ -23,6 +23,9 @@ public class Startup
services.AddInfrastructure(); services.AddInfrastructure();
services.AddPersistenceDbContext(Configuration); services.AddPersistenceDbContext(Configuration);
services.AddJWTAuthentication(Configuration); services.AddJWTAuthentication(Configuration);
services.AddMemoryCache();
DependencyInjection.MapsterSetup();
} }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

View File

@ -1,59 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Persistence.Database.Postgres.Migrations
{
/// <inheritdoc />
public partial class TechMessageMigration : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "Created",
table: "Setpoint",
type: "timestamp with time zone",
nullable: false,
comment: "Дата создания уставки",
oldClrType: typeof(DateTimeOffset),
oldType: "timestamp with time zone",
oldComment: "Дата изменения уставки");
migrationBuilder.CreateTable(
name: "TechMessage",
columns: table => new
{
EventId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id события"),
ImportantId = table.Column<int>(type: "integer", nullable: false, comment: "Id Категории важности"),
OccurrenceDate = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата возникновения"),
Depth = table.Column<double>(type: "double precision", nullable: true, comment: "Глубина забоя"),
MessageText = table.Column<string>(type: "varchar(512)", nullable: true, comment: "Текст сообщения"),
AutoDrillingSystem = table.Column<string>(type: "varchar(256)", nullable: true, comment: "Система автобурения, к которой относится сообщение"),
UserId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id пользователя за пультом бурильщика")
},
constraints: table =>
{
table.PrimaryKey("PK_TechMessage", x => x.EventId);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "TechMessage");
migrationBuilder.AlterColumn<DateTimeOffset>(
name: "Created",
table: "Setpoint",
type: "timestamp with time zone",
nullable: false,
comment: "Дата изменения уставки",
oldClrType: typeof(DateTimeOffset),
oldType: "timestamp with time zone",
oldComment: "Дата создания уставки");
}
}
}

View File

@ -12,7 +12,7 @@ using Persistence.Database.Model;
namespace Persistence.Database.Postgres.Migrations namespace Persistence.Database.Postgres.Migrations
{ {
[DbContext(typeof(PersistenceDbContext))] [DbContext(typeof(PersistenceDbContext))]
[Migration("20241126044756_TechMessageMigration")] [Migration("20241127123045_TechMessageMigration")]
partial class TechMessageMigration partial class TechMessageMigration
{ {
/// <inheritdoc /> /// <inheritdoc />
@ -27,6 +27,27 @@ namespace Persistence.Database.Postgres.Migrations
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack"); NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack");
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Persistence.Database.Entity.ADSystem", b =>
{
b.Property<Guid>("SystemId")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasComment("Id системы автобурения");
b.Property<string>("Description")
.HasColumnType("text")
.HasComment("Описание системы автобурения");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("varchar(256)")
.HasComment("Наименование системы автобурения");
b.HasKey("SystemId");
b.ToTable("ADSystem");
});
modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b => modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b =>
{ {
b.Property<Guid>("EventId") b.Property<Guid>("EventId")
@ -34,10 +55,6 @@ namespace Persistence.Database.Postgres.Migrations
.HasColumnType("uuid") .HasColumnType("uuid")
.HasComment("Id события"); .HasComment("Id события");
b.Property<string>("AutoDrillingSystem")
.HasColumnType("varchar(256)")
.HasComment("Система автобурения, к которой относится сообщение");
b.Property<double?>("Depth") b.Property<double?>("Depth")
.HasColumnType("double precision") .HasColumnType("double precision")
.HasComment("Глубина забоя"); .HasComment("Глубина забоя");
@ -47,6 +64,7 @@ namespace Persistence.Database.Postgres.Migrations
.HasComment("Id Категории важности"); .HasComment("Id Категории важности");
b.Property<string>("MessageText") b.Property<string>("MessageText")
.IsRequired()
.HasColumnType("varchar(512)") .HasColumnType("varchar(512)")
.HasComment("Текст сообщения"); .HasComment("Текст сообщения");
@ -54,15 +72,44 @@ namespace Persistence.Database.Postgres.Migrations
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasComment("Дата возникновения"); .HasComment("Дата возникновения");
b.Property<Guid>("SystemId")
.HasColumnType("uuid")
.HasComment("Id системы автобурения, к которой относится сообщение");
b.Property<Guid>("UserId") b.Property<Guid>("UserId")
.HasColumnType("uuid") .HasColumnType("uuid")
.HasComment("Id пользователя за пультом бурильщика"); .HasComment("Id пользователя за пультом бурильщика");
b.HasKey("EventId"); b.HasKey("EventId");
b.HasIndex("SystemId");
b.ToTable("TechMessage"); b.ToTable("TechMessage");
}); });
modelBuilder.Entity("Persistence.Database.Entity.TimestampedSet", b =>
{
b.Property<Guid>("IdDiscriminator")
.HasColumnType("uuid")
.HasComment("Дискриминатор ссылка на тип сохраняемых данных");
b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("timestamp with time zone")
.HasComment("Отметка времени, строго в UTC");
b.Property<string>("Set")
.IsRequired()
.HasColumnType("jsonb")
.HasComment("Набор сохраняемых данных");
b.HasKey("IdDiscriminator", "Timestamp");
b.ToTable("TimestampedSets", t =>
{
t.HasComment("Общая таблица данных временных рядов");
});
});
modelBuilder.Entity("Persistence.Database.Model.DataSaub", b => modelBuilder.Entity("Persistence.Database.Model.DataSaub", b =>
{ {
b.Property<DateTimeOffset>("Date") b.Property<DateTimeOffset>("Date")
@ -169,6 +216,17 @@ namespace Persistence.Database.Postgres.Migrations
b.ToTable("Setpoint"); b.ToTable("Setpoint");
}); });
modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b =>
{
b.HasOne("Persistence.Database.Entity.ADSystem", "System")
.WithMany()
.HasForeignKey("SystemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("System");
});
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }
} }

View File

@ -0,0 +1,83 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Persistence.Database.Postgres.Migrations
{
/// <inheritdoc />
public partial class TechMessageMigration : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ADSystem",
columns: table => new
{
SystemId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id системы автобурения"),
Name = table.Column<string>(type: "varchar(256)", nullable: false, comment: "Наименование системы автобурения"),
Description = table.Column<string>(type: "text", nullable: true, comment: "Описание системы автобурения")
},
constraints: table =>
{
table.PrimaryKey("PK_ADSystem", x => x.SystemId);
});
migrationBuilder.CreateTable(
name: "TimestampedSets",
columns: table => new
{
IdDiscriminator = table.Column<Guid>(type: "uuid", nullable: false, comment: "Дискриминатор ссылка на тип сохраняемых данных"),
Timestamp = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Отметка времени, строго в UTC"),
Set = table.Column<string>(type: "jsonb", nullable: false, comment: "Набор сохраняемых данных")
},
constraints: table =>
{
table.PrimaryKey("PK_TimestampedSets", x => new { x.IdDiscriminator, x.Timestamp });
},
comment: "Общая таблица данных временных рядов");
migrationBuilder.CreateTable(
name: "TechMessage",
columns: table => new
{
EventId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id события"),
ImportantId = table.Column<int>(type: "integer", nullable: false, comment: "Id Категории важности"),
OccurrenceDate = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата возникновения"),
Depth = table.Column<double>(type: "double precision", nullable: true, comment: "Глубина забоя"),
MessageText = table.Column<string>(type: "varchar(512)", nullable: false, comment: "Текст сообщения"),
SystemId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id системы автобурения, к которой относится сообщение"),
UserId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id пользователя за пультом бурильщика")
},
constraints: table =>
{
table.PrimaryKey("PK_TechMessage", x => x.EventId);
table.ForeignKey(
name: "FK_TechMessage_ADSystem_SystemId",
column: x => x.SystemId,
principalTable: "ADSystem",
principalColumn: "SystemId",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_TechMessage_SystemId",
table: "TechMessage",
column: "SystemId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "TechMessage");
migrationBuilder.DropTable(
name: "TimestampedSets");
migrationBuilder.DropTable(
name: "ADSystem");
}
}
}

View File

@ -24,6 +24,27 @@ namespace Persistence.Database.Postgres.Migrations
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack"); NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack");
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Persistence.Database.Entity.ADSystem", b =>
{
b.Property<Guid>("SystemId")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasComment("Id системы автобурения");
b.Property<string>("Description")
.HasColumnType("text")
.HasComment("Описание системы автобурения");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("varchar(256)")
.HasComment("Наименование системы автобурения");
b.HasKey("SystemId");
b.ToTable("ADSystem");
});
modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b => modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b =>
{ {
b.Property<Guid>("EventId") b.Property<Guid>("EventId")
@ -31,10 +52,6 @@ namespace Persistence.Database.Postgres.Migrations
.HasColumnType("uuid") .HasColumnType("uuid")
.HasComment("Id события"); .HasComment("Id события");
b.Property<string>("AutoDrillingSystem")
.HasColumnType("varchar(256)")
.HasComment("Система автобурения, к которой относится сообщение");
b.Property<double?>("Depth") b.Property<double?>("Depth")
.HasColumnType("double precision") .HasColumnType("double precision")
.HasComment("Глубина забоя"); .HasComment("Глубина забоя");
@ -44,6 +61,7 @@ namespace Persistence.Database.Postgres.Migrations
.HasComment("Id Категории важности"); .HasComment("Id Категории важности");
b.Property<string>("MessageText") b.Property<string>("MessageText")
.IsRequired()
.HasColumnType("varchar(512)") .HasColumnType("varchar(512)")
.HasComment("Текст сообщения"); .HasComment("Текст сообщения");
@ -51,15 +69,44 @@ namespace Persistence.Database.Postgres.Migrations
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasComment("Дата возникновения"); .HasComment("Дата возникновения");
b.Property<Guid>("SystemId")
.HasColumnType("uuid")
.HasComment("Id системы автобурения, к которой относится сообщение");
b.Property<Guid>("UserId") b.Property<Guid>("UserId")
.HasColumnType("uuid") .HasColumnType("uuid")
.HasComment("Id пользователя за пультом бурильщика"); .HasComment("Id пользователя за пультом бурильщика");
b.HasKey("EventId"); b.HasKey("EventId");
b.HasIndex("SystemId");
b.ToTable("TechMessage"); b.ToTable("TechMessage");
}); });
modelBuilder.Entity("Persistence.Database.Entity.TimestampedSet", b =>
{
b.Property<Guid>("IdDiscriminator")
.HasColumnType("uuid")
.HasComment("Дискриминатор ссылка на тип сохраняемых данных");
b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("timestamp with time zone")
.HasComment("Отметка времени, строго в UTC");
b.Property<string>("Set")
.IsRequired()
.HasColumnType("jsonb")
.HasComment("Набор сохраняемых данных");
b.HasKey("IdDiscriminator", "Timestamp");
b.ToTable("TimestampedSets", t =>
{
t.HasComment("Общая таблица данных временных рядов");
});
});
modelBuilder.Entity("Persistence.Database.Model.DataSaub", b => modelBuilder.Entity("Persistence.Database.Model.DataSaub", b =>
{ {
b.Property<DateTimeOffset>("Date") b.Property<DateTimeOffset>("Date")
@ -166,6 +213,17 @@ namespace Persistence.Database.Postgres.Migrations
b.ToTable("Setpoint"); b.ToTable("Setpoint");
}); });
modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b =>
{
b.HasOne("Persistence.Database.Entity.ADSystem", "System")
.WithMany()
.HasForeignKey("SystemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("System");
});
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }
} }

View File

@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace Persistence.Database.Entity;
public class ADSystem
{
[Key, Comment("Id системы автобурения")]
public Guid SystemId { get; set; }
[Required, Column(TypeName = "varchar(256)"), Comment("Наименование системы автобурения")]
public required string Name { get; set; }
[Comment("Описание системы автобурения")]
public string? Description { get; set; }
}

View File

@ -19,10 +19,13 @@ namespace Persistence.Database.Entity
public double? Depth { get; set; } public double? Depth { get; set; }
[Column(TypeName = "varchar(512)"), Comment("Текст сообщения")] [Column(TypeName = "varchar(512)"), Comment("Текст сообщения")]
public string? MessageText { get; set; } public required string MessageText { get; set; }
[Column(TypeName = "varchar(256)"), Comment("Система автобурения, к которой относится сообщение")] [Required, Comment("Id системы автобурения, к которой относится сообщение")]
public string? AutoDrillingSystem { get; set; } public required Guid SystemId { get; set; }
[Required, ForeignKey(nameof(SystemId)), Comment("Система автобурения, к которой относится сообщение")]
public virtual required ADSystem System { get; set; }
[Comment("Id пользователя за пультом бурильщика")] [Comment("Id пользователя за пультом бурильщика")]
public Guid UserId { get; set; } public Guid UserId { get; set; }

View File

@ -29,7 +29,7 @@ namespace Persistence.IntegrationTests.Controllers
{ {
Skip = 1, Skip = 1,
Take = 2, Take = 2,
SortSettings = nameof(TechMessageDto.ImportantId) SortSettings = nameof(TechMessageDto.CategoryId)
}; };
//act //act
@ -53,7 +53,7 @@ namespace Persistence.IntegrationTests.Controllers
{ {
Skip = 0, Skip = 0,
Take = 2, Take = 2,
SortSettings = nameof(TechMessageDto.ImportantId) SortSettings = nameof(TechMessageDto.CategoryId)
}; };
//act //act
@ -90,7 +90,7 @@ namespace Persistence.IntegrationTests.Controllers
//arrange //arrange
var dtos = await InsertRange(); var dtos = await InsertRange();
var systems = dtos var systems = dtos
.Select(e => e.AutoDrillingSystem) .Select(e => e.System)
.Distinct() .Distinct()
.ToArray(); .ToArray();
@ -110,7 +110,7 @@ namespace Persistence.IntegrationTests.Controllers
//arrange //arrange
dbContext.CleanupDbSet<TechMessage>(); dbContext.CleanupDbSet<TechMessage>();
var imortantId = 1; var imortantId = 1;
var autoDrillingSystem = nameof(TechMessageDto.AutoDrillingSystem); var autoDrillingSystem = nameof(TechMessageDto.System);
//act //act
var response = await techMessagesClient.GetStatistics(imortantId, autoDrillingSystem, new CancellationToken()); var response = await techMessagesClient.GetStatistics(imortantId, autoDrillingSystem, new CancellationToken());
@ -125,9 +125,9 @@ namespace Persistence.IntegrationTests.Controllers
{ {
//arrange //arrange
var imortantId = 1; var imortantId = 1;
var autoDrillingSystem = nameof(TechMessageDto.AutoDrillingSystem); var autoDrillingSystem = nameof(TechMessageDto.System);
var dtos = await InsertRange(); var dtos = await InsertRange();
var filteredDtos = dtos.Where(e => e.ImportantId == imortantId && e.AutoDrillingSystem == e.AutoDrillingSystem); var filteredDtos = dtos.Where(e => e.CategoryId == imortantId && e.System == e.System);
//act //act
var response = await techMessagesClient.GetStatistics(imortantId, autoDrillingSystem, new CancellationToken()); var response = await techMessagesClient.GetStatistics(imortantId, autoDrillingSystem, new CancellationToken());
@ -145,21 +145,21 @@ namespace Persistence.IntegrationTests.Controllers
new TechMessageDto() new TechMessageDto()
{ {
EventId = Guid.NewGuid(), EventId = Guid.NewGuid(),
ImportantId = 1, CategoryId = 1,
OccurrenceDate = DateTimeOffset.UtcNow, Timestamp = DateTimeOffset.UtcNow,
Depth = 1.11, Depth = 1.11,
MessageText = nameof(TechMessageDto.MessageText), MessageText = nameof(TechMessageDto.MessageText),
AutoDrillingSystem = nameof(TechMessageDto.AutoDrillingSystem), System = nameof(TechMessageDto.System),
UserId = Guid.NewGuid() UserId = Guid.NewGuid()
}, },
new TechMessageDto() new TechMessageDto()
{ {
EventId = Guid.NewGuid(), EventId = Guid.NewGuid(),
ImportantId = 2, CategoryId = 2,
OccurrenceDate = DateTimeOffset.UtcNow, Timestamp = DateTimeOffset.UtcNow,
Depth = 2.22, Depth = 2.22,
MessageText = nameof(TechMessageDto.MessageText), MessageText = nameof(TechMessageDto.MessageText),
AutoDrillingSystem = nameof(TechMessageDto.AutoDrillingSystem), System = nameof(TechMessageDto.System),
UserId = Guid.NewGuid() UserId = Guid.NewGuid()
} }
}; };

View File

@ -1,5 +1,7 @@
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json.Linq;
using Persistence.Database.Entity; using Persistence.Database.Entity;
using Persistence.Models; using Persistence.Models;
using Persistence.Repositories; using Persistence.Repositories;
@ -9,9 +11,13 @@ namespace Persistence.Repository.Repositories
{ {
public class TechMessagesRepository : ITechMessagesRepository public class TechMessagesRepository : ITechMessagesRepository
{ {
private static readonly string SystemCacheKey = $"{typeof(ADSystem).FullName}CacheKey";
private readonly IMemoryCache memoryCache;
private DbContext db; private DbContext db;
public TechMessagesRepository(DbContext db)
public TechMessagesRepository(DbContext db, IMemoryCache memoryCache)
{ {
this.memoryCache = memoryCache;
this.db = db; this.db = db;
} }
@ -36,36 +42,75 @@ namespace Persistence.Repository.Repositories
return dto; return dto;
} }
public async Task<int> GetStatistics(int importantId, string autoDrillingSystem, CancellationToken token) public async Task<Dictionary<string, int>> GetStatistics(int? importantId, string? autoDrillingSystem, CancellationToken token)
{ {
var query = GetQueryReadOnly(); var query = GetQueryReadOnly();
var count = await query var count = await query
.Where(e => e.ImportantId == importantId && e.AutoDrillingSystem == autoDrillingSystem) .Where(e => importantId == null || e.ImportantId == importantId)
.CountAsync(); .Where(e => autoDrillingSystem == null || e.System.Name == autoDrillingSystem)
.GroupBy(e => e.System.Name)
.ToDictionaryAsync(e => e.Key, v => v.Count());
return count; return count;
} }
public async Task<IEnumerable<string>> GetSystems(CancellationToken token) public async Task<IEnumerable<ADSystemDto>> GetSystems(CancellationToken token)
{ {
var query = GetQueryReadOnly(); var systems = await memoryCache.GetOrCreateAsync(SystemCacheKey, async f =>
var entities = await query {
.Select(e => e.AutoDrillingSystem ?? string.Empty) f.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60);
.Distinct()
.ToArrayAsync(token);
var dtos = entities.Order();
return dtos; var query = db.Set<ADSystem>();
var entities = await query.ToListAsync();
var dtos = entities.Select(e => e.Adapt<ADSystemDto>());
return dtos;
});
return systems ?? [];
} }
public async Task<int> InsertRange(IEnumerable<TechMessageDto> dtos, CancellationToken token) public async Task<int> InsertRange(IEnumerable<TechMessageDto> dtos, CancellationToken token)
{ {
var entities = dtos.Select(d => d.Adapt<TechMessage>()); var entities = dtos.Select(dto =>
{
var task = Task.Run(async () =>
{
var entity = dto.Adapt<TechMessage>();
var systems = await GetSystems(token);
var systemId = systems.FirstOrDefault(e => e.Name == dto.System)?.SystemId
?? await CreateSystem(dto.System);
entity.SystemId = systemId;
return entity;
});
task.Wait();
return task.Result;
});
await db.Set<TechMessage>().AddRangeAsync(entities, token); await db.Set<TechMessage>().AddRangeAsync(entities, token);
var result = await db.SaveChangesAsync(token); var result = await db.SaveChangesAsync(token);
return result; return result;
} }
private async Task<Guid> CreateSystem(string name)
{
memoryCache.Remove(SystemCacheKey);
var systemId = Guid.NewGuid();
var entity = new ADSystem()
{
SystemId = systemId,
Name = name
};
await db.Set<ADSystem>().AddAsync(entity);
await db.SaveChangesAsync();
return Guid.NewGuid();
}
} }
} }

View File

@ -1,35 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using Persistence.Models;
namespace Persistence.API
{
/// <summary>
/// Интерфейс для API сообщений о состояниях работы систем автобурения (АБ)
/// </summary>
public interface ITechMessages : ITableDataApi<TechMessageDto, RequestDto>
{
/// <summary>
/// Добавление новых сообщений
/// </summary>
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<ActionResult<int>> InsertRange(IEnumerable<TechMessageDto> dtos, CancellationToken token);
/// <summary>
/// Получение списка систем АБ
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
Task<ActionResult<IEnumerable<string>>> GetSystems(CancellationToken token);
/// <summary>
/// Получение статистики
/// </summary>
/// <param name="importantId">Id Категории важности</param>
/// <param name="autoDrillingSystem">Система АБ</param>
/// <param name="token"></param>
/// <returns></returns>
Task<ActionResult<int>> GetStatistics(int importantId, string autoDrillingSystem, CancellationToken token);
}
}

View File

@ -0,0 +1,22 @@
namespace Persistence.Models;
/// <summary>
/// Модель системы автобурения
/// </summary>
public class ADSystemDto
{
/// <summary>
/// Ключ
/// </summary>
public Guid SystemId { get; set; }
/// <summary>
/// Наименование
/// </summary>
public required string Name { get; set; }
/// <summary>
/// Описание
/// </summary>
public string? Description { get; set; }
}

View File

@ -1,4 +1,6 @@
namespace Persistence.Models using System.ComponentModel.DataAnnotations;
namespace Persistence.Models
{ {
/// <summary> /// <summary>
/// Модель технологического сообщения /// Модель технологического сообщения
@ -8,32 +10,39 @@
/// <summary> /// <summary>
/// Id события /// Id события
/// </summary> /// </summary>
[Required]
public Guid EventId { get; set; } public Guid EventId { get; set; }
/// <summary> /// <summary>
/// Id Категории важности /// Id Категории важности
/// </summary> /// </summary>
public int ImportantId { get; set; } [Range(0, int.MaxValue, ErrorMessage = "Id Категории важности не может быть меньше 0")]
public int CategoryId { get; set; }
/// <summary> /// <summary>
/// Дата возникновения /// Дата возникновения
/// </summary> /// </summary>
public DateTimeOffset OccurrenceDate { get; set; } public DateTimeOffset Timestamp { get; set; }
/// <summary> /// <summary>
/// Глубина забоя /// Глубина забоя
/// </summary> /// </summary>
[Range(0, double.MaxValue, ErrorMessage = "Глубина забоя не может быть меньше 0")]
public double? Depth { get; set; } public double? Depth { get; set; }
/// <summary> /// <summary>
/// Текст сообщения /// Текст сообщения
/// </summary> /// </summary>
public string? MessageText { get; set; } [Required]
[StringLength(512, MinimumLength = 1, ErrorMessage = "Допустимая длина текста сообщения от 1 до 512 символов")]
public required string MessageText { get; set; }
/// <summary> /// <summary>
/// Система автобурения, к которой относится сообщение /// Система автобурения, к которой относится сообщение
/// </summary> /// </summary>
public string? AutoDrillingSystem { get; set; } [Required]
[StringLength(256, MinimumLength = 1, ErrorMessage = "Допустимая длина наименования системы АБ от 1 до 256 символов")]
public required string System { get; set; }
/// <summary> /// <summary>
/// Id пользователя за пультом бурильщика /// Id пользователя за пультом бурильщика

View File

@ -1,4 +1,5 @@
using Persistence.Models; using System.Threading.Tasks;
using Persistence.Models;
namespace Persistence.Repositories namespace Persistence.Repositories
{ {
@ -28,7 +29,7 @@ namespace Persistence.Repositories
/// </summary> /// </summary>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<string>> GetSystems(CancellationToken token); Task<IEnumerable<ADSystemDto>> GetSystems(CancellationToken token);
/// <summary> /// <summary>
/// Получение количества сообщений по категориям и системам автобурения /// Получение количества сообщений по категориям и системам автобурения
@ -37,6 +38,6 @@ namespace Persistence.Repositories
/// <param name="autoDrillingSystem">Система автобурения</param> /// <param name="autoDrillingSystem">Система автобурения</param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<int> GetStatistics(int importantId, string autoDrillingSystem, CancellationToken token); Task<Dictionary<string, int>> GetStatistics(int? importantId, string? autoDrillingSystem, CancellationToken token);
} }
} }