From 79108c754adef288f2f37ef9986d943eb787f82e Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Wed, 7 Sep 2022 18:01:39 +0500 Subject: [PATCH] fixed --- .../Requests/SubsystemOperationTimeRequest.cs | 3 + .../ISubsystemOperationTimeService.cs | 30 +- AsbCloudDb/Model/Subsystems/Subsystem.cs | 13 +- .../Subsystems/SubsystemOperationTime.cs | 19 +- ...SubsystemOperationTimeBackgroundService.cs | 267 ++++++++++-------- .../SubsystemOperationTimeService.cs | 174 ++++++------ .../Services/Subsystems/SubsystemService.cs | 23 +- .../Subsystems/AdminSubsystemController.cs | 2 +- .../SubsystemOperationTimeController.cs | 8 +- 9 files changed, 282 insertions(+), 257 deletions(-) diff --git a/AsbCloudApp/Requests/SubsystemOperationTimeRequest.cs b/AsbCloudApp/Requests/SubsystemOperationTimeRequest.cs index 2cef174a..3a4c3e56 100644 --- a/AsbCloudApp/Requests/SubsystemOperationTimeRequest.cs +++ b/AsbCloudApp/Requests/SubsystemOperationTimeRequest.cs @@ -47,14 +47,17 @@ namespace AsbCloudApp.Requests /// информация попадает в выборку, если интервал выборки частично или полностью пересекается с запрашиваемым интервалом /// public const int SelectModeOuter = 0; + /// /// информация попадает в выборку, если интервал выборки строго полностью пересекается с запрашиваемым интервалом. /// public const int SelectModeInner = 1; + /// /// аналогично outer, но интервалы в частично пересекающиеся укорачиваются по границам интервала выборки. /// public const int SelectModeTrim = 2; + /// /// Режим выборки элементов /// diff --git a/AsbCloudApp/Services/Subsystems/ISubsystemOperationTimeService.cs b/AsbCloudApp/Services/Subsystems/ISubsystemOperationTimeService.cs index dbc79fd0..07e41895 100644 --- a/AsbCloudApp/Services/Subsystems/ISubsystemOperationTimeService.cs +++ b/AsbCloudApp/Services/Subsystems/ISubsystemOperationTimeService.cs @@ -1,19 +1,41 @@ using AsbCloudApp.Data.Subsystems; using AsbCloudApp.Requests; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; namespace AsbCloudApp.Services.Subsystems { #nullable enable + /// + /// Получение инфо о наработке подсистем + /// public interface ISubsystemOperationTimeService - { + { + /// + /// Статистика о наработке подсистем + /// + /// + /// + /// Task?> GetStatAsync(SubsystemOperationTimeRequest request, CancellationToken token); + + /// + /// Удаление наработки по подсистемам. + /// Если удаляется конец, то фоновый сервис подсчета наработки восстановит эти данные. + /// Может потребоваться для запуска повторного расчета по новому алгоритму. + /// + /// + /// + /// Task DeleteAsync(SubsystemOperationTimeRequest request, CancellationToken token); + + /// + /// Интервалы работы подсистем + /// + /// + /// + /// Task?> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token); } #nullable disable diff --git a/AsbCloudDb/Model/Subsystems/Subsystem.cs b/AsbCloudDb/Model/Subsystems/Subsystem.cs index 70160f6e..37ac9fed 100644 --- a/AsbCloudDb/Model/Subsystems/Subsystem.cs +++ b/AsbCloudDb/Model/Subsystems/Subsystem.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; +using System.ComponentModel.DataAnnotations; using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations.Schema; @@ -9,9 +6,8 @@ namespace AsbCloudDb.Model.Subsystems { [Table("t_subsystem"), Comment("Описание подсистем")] public class Subsystem : IId - { - [Key] - [Column("id")] + { + [Column("id"), Key] public int Id { get; set; } [Column("name")] @@ -22,6 +18,5 @@ namespace AsbCloudDb.Model.Subsystems [StringLength(255)] public string? Description { get; set; } - } - + } } diff --git a/AsbCloudDb/Model/Subsystems/SubsystemOperationTime.cs b/AsbCloudDb/Model/Subsystems/SubsystemOperationTime.cs index e8b0c35b..9fd1833c 100644 --- a/AsbCloudDb/Model/Subsystems/SubsystemOperationTime.cs +++ b/AsbCloudDb/Model/Subsystems/SubsystemOperationTime.cs @@ -9,8 +9,7 @@ namespace AsbCloudDb.Model.Subsystems [Table("t_subsystem_operation_time"), Comment("наработки подсистем")] public partial class SubsystemOperationTime : IId { - [Key] - [Column("id")] + [Column("id"), Key] public int Id { get; set; } [Column("id_telemetry"), Comment("ИД телеметрии по которой выдается информация")] @@ -20,23 +19,23 @@ namespace AsbCloudDb.Model.Subsystems public int IdSubsystem { get; set; } [Column("date_start"), Comment("дата/время включения подсистемы")] - public DateTimeOffset DateStart { get; set; } + public DateTimeOffset DateStart { get; set; } + [Column("date_end"), Comment("дата/время выключения подсистемы")] - public DateTimeOffset DateEnd { get; set; } + public DateTimeOffset DateEnd { get; set; } + [Column("depth_start"), Comment("глубина забоя на момент включения подсистемы")] public float? DepthStart { get; set; } + [Column("depth_end"), Comment("глубина забоя на момент выключения подсистемы")] public float? DepthEnd { get; set; } [JsonIgnore] - [ForeignKey(nameof(IdSubsystem))] - public virtual Subsystem Subsystem { get; set; } + [ForeignKey(nameof(IdSubsystem))] + public virtual Subsystem Subsystem { get; set; } = null!; [JsonIgnore] [ForeignKey(nameof(IdTelemetry))] - public virtual Telemetry Telemetry { get; set; } - - - + public virtual Telemetry Telemetry { get; set; } = null!; } } diff --git a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeBackgroundService.cs b/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeBackgroundService.cs index 5885f8a1..0648c32f 100644 --- a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeBackgroundService.cs +++ b/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeBackgroundService.cs @@ -7,7 +7,6 @@ using Npgsql; using System; using System.Collections.Generic; using System.Data; -using System.Data.SqlClient; using System.Diagnostics; using System.Linq; using System.Threading; @@ -26,17 +25,18 @@ namespace AsbCloudInfrastructure.Services.Subsystems { connectionString = configuration.GetConnectionString("DefaultConnection"); } + protected override async Task ExecuteAsync(CancellationToken token) { - var timeToStartAnalysis = DateTime.Now; + var timeToStart = DateTime.Now; var options = new DbContextOptionsBuilder() .UseNpgsql(connectionString) .Options; while (!token.IsCancellationRequested) { - if (DateTime.Now > timeToStartAnalysis) + if (DateTime.Now > timeToStart) { - timeToStartAnalysis = DateTime.Now + period; + timeToStart = DateTime.Now + period; try { using var context = new AsbCloudDbContext(options); @@ -49,7 +49,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems } GC.Collect(); } - var ms = (int)(timeToStartAnalysis - DateTime.Now).TotalMilliseconds; + var ms = (int)(timeToStart - DateTime.Now).TotalMilliseconds; ms = ms > 100 ? ms : 100; await Task.Delay(ms, token).ConfigureAwait(false); } @@ -76,7 +76,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems .Select(t => t.Id) .ToListAsync(token); - var JounedlastDetectedDates = telemetryIds + var telemetryLastDetectedDates = telemetryIds .GroupJoin(lastDetectedDates, t => t, o => o.IdTelemetry, @@ -85,8 +85,9 @@ namespace AsbCloudInfrastructure.Services.Subsystems IdTelemetry = outer, inner.SingleOrDefault()?.LastDate, }); + var affected = 0; - foreach (var item in JounedlastDetectedDates) + foreach (var item in telemetryLastDetectedDates) { var newOperationsSaub = await OperationTimeSaubAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token); if (newOperationsSaub?.Any() == true) @@ -103,139 +104,157 @@ namespace AsbCloudInfrastructure.Services.Subsystems } return affected; } - private static async Task?> OperationTimeSaubAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token) - { - var operationTimeSaub = - $"select tt.date, tt.mode, tt.well_depth" + - $" from (select date, mode, well_depth, lag(mode,1) over (order by date) as mode_prev" + - $" from t_telemetry_data_saub where id_telemetry = @idTelemetry) as tt" + - $" where tt.mode != tt.mode_prev and tt.date >= @begin order by tt.date;"; - using var command = db.Database.GetDbConnection().CreateCommand(); - command.CommandText = operationTimeSaub; - var telemetry = new NpgsqlParameter("@idTelemetry", idTelemetry); - command.Parameters.Add(telemetry); - var dateStart = new NpgsqlParameter("@begin", begin); - command.Parameters.Add(dateStart); - db.Database.OpenConnection(); - using var result = await command.ExecuteReaderAsync(token); - var telemetryOpearationSaubSubsystems = new List(); - if (result.HasRows) + private static async Task> OperationTimeSaubAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token) + { + static int? GetSubsytemId(short mode) { + return mode +1; + } + + var query = + $"select tt.date, tt.mode, tt.well_depth " + + $"from ( " + + $" select " + + $" date, " + + $" mode, " + + $" well_depth, " + + $" lag(mode,1) over (order by date) as mode_prev " + + $" from t_telemetry_data_saub " + + $" where id_telemetry = @idTelemetry " + + $" order by date ) as tt " + + $"where (tt.mode_prev is null or tt.mode != tt.mode_prev) and tt.date >= @begin " + + $"order by tt.date;"; + + var idTelemetryParam = new NpgsqlParameter("@idTelemetry", idTelemetry); + var beginParam = new NpgsqlParameter("@begin", begin); + + await db.Database.OpenConnectionAsync(token); + using var command = db.Database.GetDbConnection().CreateCommand(); + command.CommandText = query; + command.Parameters.Add(idTelemetryParam); + command.Parameters.Add(beginParam); + + using var result = await command.ExecuteReaderAsync(token); + + var subsystemOperationTime = new List(32); + + if (result.Read()) + { + var mode = result.GetFieldValue(1); + var idSubsystem = GetSubsytemId(mode); + var dateStart = result.GetFieldValue(0); + var depthStart = result.GetFieldValue(2); while (result.Read()) { - var itemEntity = new SubsystemsSpinWithDepth() + var dateEnd = result.GetFieldValue(0); + var depthEnd = result.GetFieldValue(2); + if (idSubsystem.HasValue) { - Date = result.GetFieldValue(0), - IdSubsystem = result.GetFieldValue(1)+1, - Depth = result.GetFieldValue(2) - }; - telemetryOpearationSaubSubsystems.Add(itemEntity); + var operationTimeItem = new SubsystemOperationTime() + { + IdTelemetry = idTelemetry, + IdSubsystem = idSubsystem.Value, + DateStart = dateStart, + DateEnd = dateEnd, + DepthStart = depthStart, + DepthEnd = depthEnd + }; + subsystemOperationTime.Add(operationTimeItem); + } + mode = result.GetFieldValue(1); + idSubsystem = GetSubsytemId(mode); + dateStart = dateEnd; + depthStart = depthEnd; } } - var resultSubsystemOperationTime = new List(); - var firstItem = telemetryOpearationSaubSubsystems.FirstOrDefault(); - if (firstItem is null) - return null; - int idSubsystem = firstItem.IdSubsystem; - DateTimeOffset dateBegin = firstItem.Date; - float? depthStart = firstItem.Depth; - for (int i = 1; i < telemetryOpearationSaubSubsystems.Count; i++) - { - if (telemetryOpearationSaubSubsystems[i].IdSubsystem != idSubsystem) - { - var operationTimeItem = new SubsystemOperationTime() - { - IdTelemetry = idTelemetry, - DateStart = dateBegin, - IdSubsystem = telemetryOpearationSaubSubsystems[i - 1].IdSubsystem, - DateEnd = telemetryOpearationSaubSubsystems[i].Date, - DepthStart = depthStart, - DepthEnd = telemetryOpearationSaubSubsystems[i].Depth - - }; - dateBegin = telemetryOpearationSaubSubsystems[i].Date; - depthStart = telemetryOpearationSaubSubsystems[i].Depth; - idSubsystem = telemetryOpearationSaubSubsystems[i].IdSubsystem; - resultSubsystemOperationTime.Add(operationTimeItem); - - } - } - return resultSubsystemOperationTime; + return subsystemOperationTime; } + private static async Task?> OperationTimeSpinAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token) { - Predicate isSubsystemTorqueState = (int state) => state == 7; - Predicate isSubsystemTorqueMode = (short mode) => (mode & 2) > 0; - Predicate isSubsystemSpin = (int state) => state != 0 & state != 6 & state != 7; - var operationTimeSpinWithDepth = - $"select tspin.\"date\", tspin.\"mode\", tspin.\"state\", tsaub.\"well_depth\"" + - $" from (select \"date\" ,\"mode\" ,lag(mode, 1) over (order by \"date\") as mode_pre, state , " + - $"lag(state, 1) over (order by \"date\") as state_pre from t_telemetry_data_spin where id_telemetry = @idTelemetry and date >= @begin) as tspin " + - $"join (select \"date\", well_depth from t_telemetry_data_saub where id_telemetry = @idTelemetry and date >= @begin) as tsaub " + - $"on EXTRACT(EPOCH from tspin.date) = EXTRACT(EPOCH from tsaub.date) " + - $"where mode!=mode_pre or state != state_pre order by \"date\";"; - using var command = db.Database.GetDbConnection().CreateCommand(); - command.CommandText = operationTimeSpinWithDepth; - var telemetry = new NpgsqlParameter("@idTelemetry", idTelemetry); - command.Parameters.Add(telemetry); - var dateStart = new NpgsqlParameter("@begin", begin); - command.Parameters.Add(dateStart); - db.Database.OpenConnection(); - using var result = await command.ExecuteReaderAsync(token); - var telemetryOpearationSpinSubsystems = new List(); - if (result.HasRows) + static int? GetSubsytemId(short mode, int state) { + if (state == 7 && (mode & 2) > 0) + return idSubsytemTorqueMaster; + + if (state != 0 & state != 6 & state != 7) + return idSubsytemSpinMaster; + + return null; + } + + var query = + $"select " + + $" tspin.date, " + + $" tspin.mode, " + + $" tspin.state, " + + $" tsaub.well_depth " + + $"from ( " + + $" select " + + $" date, " + + $" mode, " + + $" lag(mode, 1) over (order by date) as mode_pre, " + + $" state, " + + $" lag(state, 1) over (order by date) as state_pre " + + $" from t_telemetry_data_spin " + + $" where id_telemetry = @idTelemetry and date >= @begin" + + $" order by date ) as tspin " + + $"left outer join ( " + + $" select " + + $" date, " + + $" well_depth " + + $" from t_telemetry_data_saub " + + $" where id_telemetry = @idTelemetry and date >= @begin) as tsaub " + + $"on EXTRACT(EPOCH from tspin.date) = EXTRACT(EPOCH from tsaub.date) " + + $"where mode_pre is null or state_pre is null or mode != mode_pre or state != state_pre " + + $"order by date;"; + + var idTelemetryParam = new NpgsqlParameter("@idTelemetry", idTelemetry); + var beginParam = new NpgsqlParameter("@begin", begin); + + await db.Database.OpenConnectionAsync(token); + using var command = db.Database.GetDbConnection().CreateCommand(); + command.CommandText = query; + command.Parameters.Add(idTelemetryParam); + command.Parameters.Add(beginParam); + + using var result = await command.ExecuteReaderAsync(token); + + var subsystemOperationTime = new List(32); + + if (result.Read()) + { + var mode = result.GetFieldValue(1); + var state = result.GetFieldValue(2); + var idSubsystem = GetSubsytemId(mode, state); + var dateStart = result.GetFieldValue(0); + var depthStart = result.GetFieldValue(3); + while (result.Read()) { - var itemEntity = new SubsystemsSpinWithDepth() + var dateEnd = result.GetFieldValue(0); + var depthEnd = result.GetFieldValue(3); + if (idSubsystem.HasValue) { - Date = result.GetFieldValue(0), - Mode = result.GetFieldValue(1), - State = result.GetFieldValue(2), - Depth = result.GetFieldValue(3) - }; - int? subsystemId = isSubsystemTorqueState(itemEntity.State) && isSubsystemTorqueMode(itemEntity.Mode) - ? idSubsytemTorqueMaster - : isSubsystemSpin(itemEntity.State) - ? idSubsytemSpinMaster - : 0; - if (subsystemId.HasValue) - { - itemEntity.IdSubsystem = subsystemId.Value; - telemetryOpearationSpinSubsystems.Add(itemEntity); + var operationTimeItem = new SubsystemOperationTime() + { + IdTelemetry = idTelemetry, + IdSubsystem = idSubsystem.Value, + DateStart = dateStart, + DateEnd = dateEnd, + DepthStart = depthStart, + DepthEnd = depthEnd + }; + subsystemOperationTime.Add(operationTimeItem); } + mode = result.GetFieldValue(1); + state = result.GetFieldValue(2); + idSubsystem = GetSubsytemId(mode, state); + dateStart = dateEnd; + depthStart = depthEnd; } } - var resultSubsystemOperationTime = new List(); - var firstItem = telemetryOpearationSpinSubsystems.FirstOrDefault(); - if (firstItem is null) - return null; - int idSubsystem = firstItem.IdSubsystem; - DateTimeOffset dateBegin = firstItem.Date; - float? depthStart = firstItem.Depth; - for (int i = 1; i < telemetryOpearationSpinSubsystems.Count; i++) - { - if (telemetryOpearationSpinSubsystems[i].IdSubsystem != idSubsystem) - { - var operationTimeItem = new SubsystemOperationTime() - { - IdTelemetry = idTelemetry, - DateStart = dateBegin, - IdSubsystem = telemetryOpearationSpinSubsystems[i - 1].IdSubsystem, - DateEnd = telemetryOpearationSpinSubsystems[i].Date, - DepthStart = depthStart, - DepthEnd = telemetryOpearationSpinSubsystems[i].Depth - }; - dateBegin = telemetryOpearationSpinSubsystems[i].Date; - depthStart = telemetryOpearationSpinSubsystems[i].Depth; - idSubsystem = telemetryOpearationSpinSubsystems[i].IdSubsystem; - if (telemetryOpearationSpinSubsystems[i - 1].IdSubsystem != 0) - { - resultSubsystemOperationTime.Add(operationTimeItem); - } - } - } - return resultSubsystemOperationTime; + return subsystemOperationTime; } } #nullable disable diff --git a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeService.cs b/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeService.cs index 150970f2..9bfe0b85 100644 --- a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeService.cs +++ b/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeService.cs @@ -29,6 +29,8 @@ namespace AsbCloudInfrastructure.Services.Subsystems this.wellService = wellService; this.subsystemService = subsystemService; } + + /// public async Task DeleteAsync(SubsystemOperationTimeRequest request, CancellationToken token) { var well = await wellService.GetOrDefaultAsync(request.IdWell, token); @@ -41,39 +43,40 @@ namespace AsbCloudInfrastructure.Services.Subsystems return await db.SaveChangesAsync(token); } + /// public async Task?> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token) { var well = await wellService.GetOrDefaultAsync(request.IdWell, token); if (well?.IdTelemetry is null || well.Timezone is null) return null; + var query = BuildQuery(request); + if (query is null) return null; + + IEnumerable data = await query.ToListAsync(token); + if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeInner) { if (request.GtDate is not null) - query = query.Where(o => o.DateStart >= request.GtDate.Value || o.DateEnd >= request.GtDate.Value); + data = data.Where(o => o.DateStart >= request.GtDate.Value); if (request.LtDate is not null) - query = query.Where(o => o.DateEnd <= request.LtDate.Value || o.DateStart <= request.LtDate.Value); + data = data.Where(o => o.DateEnd <= request.LtDate.Value); } - if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeTrim) - { - if (!request.GtDate.HasValue) - throw new ArgumentNullException(nameof(request.GtDate)); - var begin = request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); - if (!request.LtDate.HasValue) - throw new ArgumentNullException(nameof(request.LtDate)); - var end = request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); - IEnumerable? data = query.ToList(); - data = Trim(data, begin, end); - if (data is not null) - return data.Select(o => Convert(o, well)); - return null; + else if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeTrim) + { + var begin = request.GtDate?.ToUtcDateTimeOffset(well.Timezone.Hours); + var end = request.LtDate?.ToUtcDateTimeOffset(well.Timezone.Hours); + data = Trim(data, begin, end); } - var dtos = query.Select(o => Convert(o, well)); + + var dtos = data.Select(o => Convert(o, well)); return dtos; } + + /// public async Task?> GetStatAsync(SubsystemOperationTimeRequest request, CancellationToken token) { request.SelectMode = SubsystemOperationTimeRequest.SelectModeTrim; @@ -83,110 +86,104 @@ namespace AsbCloudInfrastructure.Services.Subsystems var statList = CalcStat(data, request); return statList; } - private IEnumerable? Trim(IEnumerable? data, DateTimeOffset gtDate, DateTimeOffset ltDate) + + private static IEnumerable Trim(IEnumerable data, DateTimeOffset? gtDate, DateTimeOffset? ltDate) { - if (data is null) - return null; - var ItemsNormal = data.Where(q => - (q.DateStart >= gtDate) && (q.DateEnd <= ltDate)).ToList(); - var itemsToTrim = data.Where(q => - q.DateStart < gtDate || ltDate < q.DateEnd) - .Select(o => new SubsystemOperationTime + var items = data.Select((item) => + { + if (gtDate.HasValue && item.DateStart < gtDate.Value) { - Id = o.Id, - DateStart = gtDate < o.DateStart ? o.DateStart : gtDate, - DateEnd = ltDate > o.DateEnd ? o.DateEnd : ltDate, - IdSubsystem = o.IdSubsystem, - IdTelemetry = o.IdTelemetry, - DepthStart = gtDate > o.DateEnd ? o.DepthStart : null, - DepthEnd = ltDate < o.DateStart ? o.DepthEnd : null, - Subsystem = o.Subsystem, - Telemetry = o.Telemetry - }) - .ToList(); - ItemsNormal.AddRange(itemsToTrim); - return ItemsNormal.OrderBy(o => o.DateStart).ToList(); + item.DateStart = gtDate.Value; + item.DepthStart = null; + } + if (ltDate.HasValue && item.DateEnd > ltDate.Value) + { + item.DateEnd = ltDate.Value; + item.DepthEnd = null; + } + return item; + }); + + return items; } - private IEnumerable CalcStat(IEnumerable listOperationTimeSubsystems, SubsystemOperationTimeRequest request) + + private IEnumerable CalcStat(IEnumerable dtos, SubsystemOperationTimeRequest request) { - var result = new List(); - var groupedDataSubsystems = listOperationTimeSubsystems - .GroupBy(x => x.IdSubsystem); - var periodGroupTotal = groupedDataSubsystems - .Sum(g => g.Sum(o=> (o.DateEnd - o.DateStart).TotalHours)); - var gtDate = request.GtDate ?? listOperationTimeSubsystems.Min(d => d.DateStart); - var ltDate = request.LtDate ?? listOperationTimeSubsystems.Max(d => d.DateEnd); - var periodRequest = listOperationTimeSubsystems - .Sum(o => (o.DateEnd - o.DateStart).TotalHours); - foreach (var item in groupedDataSubsystems) - { - var periodGroup = item.Sum(g => (g.DateEnd - g.DateStart).TotalHours); - int idSubsystem = item.First().IdSubsystem; + var groupedDataSubsystems = dtos + .GroupBy(o => o.IdSubsystem); + + var periodGroupTotal = dtos.Sum(o => (o.DateEnd - o.DateStart).TotalHours); + + var gtDate = request.GtDate ?? dtos.Min(o => o.DateStart); + var ltDate = request.LtDate ?? dtos.Max(o => o.DateEnd); + + var periodRequest = (ltDate - gtDate).TotalHours; + + var result = groupedDataSubsystems.Select(item => + { + var periodGroup = item.Sum(o => (o.DateEnd - o.DateStart).TotalHours); var subsystemStat = new SubsystemStatDto() { - IdSubsystem = idSubsystem, - SubsystemName = subsystemService.GetOrDefault(idSubsystem)?.Name ?? "unknown", - UsedTimeHours =periodGroup, - KUsage = 1d*periodGroup / periodRequest, - K2 = 1d*periodGroup / periodGroupTotal, + IdSubsystem = item.Key, + SubsystemName = subsystemService.GetOrDefault(item.Key)?.Name ?? "unknown", + UsedTimeHours = periodGroup, + KUsage = 1d * periodGroup / periodRequest, + K2 = 1d * periodGroup / periodGroupTotal, }; - result.Add(subsystemStat); - } + return subsystemStat; + }); + return result; } + private IQueryable? BuildQuery(SubsystemOperationTimeRequest request) { + if (request.SelectMode > 0 && request.GtDate is null && request.LtDate is null) + return null; + var well = wellService.GetOrDefault(request.IdWell); if (well?.IdTelemetry is null || well.Timezone is null) return null; + var query = db.SubsystemOperationTimes - .Include(o => o.Subsystem) - .Where(o => o.IdTelemetry == well.IdTelemetry); - DateTimeOffset gtDateWellTime; - DateTimeOffset ltDateWellTime; + .Include(o => o.Subsystem) + .Where(o => o.IdTelemetry == well.IdTelemetry) + .AsNoTracking(); + if (request.IdsSubsystems?.Any() == true) query = query.Where(o => request.IdsSubsystems.Contains(o.IdSubsystem)); - if (request.GtDate is not null && request.LtDate is not null) + // # Dates range condition + // [GtDate LtDate] + // [DateStart DateEnd] [DateStart DateEnd] + if (request.GtDate.HasValue) { - gtDateWellTime = request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); - ltDateWellTime = request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); - //query = query.Where(o => (o.DateStart >= gtDateWellTime) - //|| (o.DateEnd <= ltDateWellTime)); - query = query.Where(q => - (q.DateStart < gtDateWellTime && q.DateEnd <= ltDateWellTime && q.DateEnd > gtDateWellTime) || - (q.DateStart >= gtDateWellTime && q.DateEnd > ltDateWellTime && q.DateStart < ltDateWellTime) || - (q.DateStart < gtDateWellTime && q.DateEnd > ltDateWellTime) || - (q.DateStart >= gtDateWellTime && q.DateEnd <= ltDateWellTime)); - } - else if (request.GtDate is not null) - { - gtDateWellTime = request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); - query = query.Where(o => o.DateStart >= gtDateWellTime); + DateTimeOffset gtDate = request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); + query = query.Where(o => o.DateEnd >= gtDate); } - else if (request.LtDate is not null) + if (request.LtDate.HasValue) { - ltDateWellTime = request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); - query = query.Where(o => o.DateEnd <= ltDateWellTime); + DateTimeOffset ltDate = request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); + query = query.Where(o => o.DateStart <= ltDate); } - - - if (request.GtDepth is not null) - query = query.Where(o => o.DepthStart >= request.GtDepth.Value); - if (request.LtDepth is not null) - query = query.Where(o => o.DepthEnd <= request.LtDepth.Value); - + if (request.GtDepth.HasValue) + query = query.Where(o => o.DepthEnd >= request.GtDepth.Value); + + if (request.LtDepth.HasValue) + query = query.Where(o => o.DepthStart <= request.LtDepth.Value); if (request?.SortFields?.Any() == true) { query = query.SortBy(request.SortFields); } else + { query = query .OrderBy(o => o.DateStart) .ThenBy(o => o.DepthStart); + } if (request?.Skip > 0) query = query.Skip((int)request.Skip); @@ -198,7 +195,8 @@ namespace AsbCloudInfrastructure.Services.Subsystems return query; } - private SubsystemOperationTimeDto Convert(SubsystemOperationTime operationTime, WellDto well) + + private static SubsystemOperationTimeDto Convert(SubsystemOperationTime operationTime, WellDto well) { var dto = operationTime.Adapt(); dto.DateStart = operationTime.DateStart.ToRemoteDateTime(well.Timezone.Hours); diff --git a/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs b/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs index 5f35a827..749dbbdf 100644 --- a/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs +++ b/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs @@ -27,21 +27,17 @@ namespace AsbCloudInfrastructure.Services.Subsystems var well = await wellService.GetOrDefaultAsync(idWell, token); if (well?.IdTelemetry is null || well.Timezone is null) return null; - var wellSubsystem = await dbContext.SubsystemOperationTimes + var entities = await dbContext.SubsystemOperationTimes .Include(e => e.Subsystem) .AsNoTracking() .Where(o => o.IdTelemetry == well.IdTelemetry) - .DistinctBy(o => o.IdSubsystem) - .Select(d => Convert( new () - { - Id = d.Subsystem.Id, - Name = d.Subsystem.Name, - Description = d.Subsystem.Description, - - })) - .ToListAsync(token); - return wellSubsystem; + .Select(o => o.Subsystem) + .Distinct() + .ToArrayAsync(token); + var dtos = entities.Select(e => e.Adapt()); + return dtos; } + public async Task?> GetSubsystemAsync(int? idWell, CancellationToken token) { if (idWell.HasValue) @@ -52,11 +48,6 @@ namespace AsbCloudInfrastructure.Services.Subsystems var subsystem = await GetAllAsync(token); return subsystem; } - new private static SubsystemDto Convert(Subsystem subsystem) - { - var dto = subsystem.Adapt(); - return dto; - } } #nullable disable } diff --git a/AsbCloudWebApi/Controllers/Subsystems/AdminSubsystemController.cs b/AsbCloudWebApi/Controllers/Subsystems/AdminSubsystemController.cs index 3663f5df..dc7ac408 100644 --- a/AsbCloudWebApi/Controllers/Subsystems/AdminSubsystemController.cs +++ b/AsbCloudWebApi/Controllers/Subsystems/AdminSubsystemController.cs @@ -19,5 +19,5 @@ namespace AsbCloudWebApi.Controllers.Subsystems { } } - } +} diff --git a/AsbCloudWebApi/Controllers/Subsystems/SubsystemOperationTimeController.cs b/AsbCloudWebApi/Controllers/Subsystems/SubsystemOperationTimeController.cs index d54fe10c..881e738b 100644 --- a/AsbCloudWebApi/Controllers/Subsystems/SubsystemOperationTimeController.cs +++ b/AsbCloudWebApi/Controllers/Subsystems/SubsystemOperationTimeController.cs @@ -21,13 +21,11 @@ namespace AsbCloudWebApi.Controllers.Subsystems { private readonly ISubsystemOperationTimeService subsystemOperationTimeService; private readonly IWellService wellService; - private readonly ICrudService subsystemServiceCrud; private readonly ISubsystemService subsystemService; - public SubsystemOperationTimeController(ISubsystemOperationTimeService subsystemOperationTimeService, IWellService wellService, ICrudService subsystemServiceCrud, ISubsystemService subsystemService) + public SubsystemOperationTimeController(ISubsystemOperationTimeService subsystemOperationTimeService, IWellService wellService, ISubsystemService subsystemService) { this.subsystemOperationTimeService = subsystemOperationTimeService; this.wellService = wellService; - this.subsystemServiceCrud = subsystemServiceCrud; this.subsystemService = subsystemService; } /// @@ -53,8 +51,8 @@ namespace AsbCloudWebApi.Controllers.Subsystems if (idWell.HasValue) if (!await UserHasAccesToWellAsync(idWell.Value, token)) return Forbid(); - var result = await subsystemService.GetSubsystemAsync(idWell, token); - return Ok(result); + var result = await subsystemService.GetSubsystemAsync(idWell, token); + return Ok(result); } ///