This commit is contained in:
ngfrolov 2022-09-07 18:01:39 +05:00
parent 4f27adf9ea
commit 79108c754a
9 changed files with 282 additions and 257 deletions

View File

@ -47,14 +47,17 @@ namespace AsbCloudApp.Requests
/// информация попадает в выборку, если интервал выборки частично или полностью пересекается с запрашиваемым интервалом /// информация попадает в выборку, если интервал выборки частично или полностью пересекается с запрашиваемым интервалом
/// </summary> /// </summary>
public const int SelectModeOuter = 0; public const int SelectModeOuter = 0;
/// <summary> /// <summary>
/// информация попадает в выборку, если интервал выборки строго полностью пересекается с запрашиваемым интервалом. /// информация попадает в выборку, если интервал выборки строго полностью пересекается с запрашиваемым интервалом.
/// </summary> /// </summary>
public const int SelectModeInner = 1; public const int SelectModeInner = 1;
/// <summary> /// <summary>
/// аналогично outer, но интервалы в частично пересекающиеся укорачиваются по границам интервала выборки. /// аналогично outer, но интервалы в частично пересекающиеся укорачиваются по границам интервала выборки.
/// </summary> /// </summary>
public const int SelectModeTrim = 2; public const int SelectModeTrim = 2;
/// <summary> /// <summary>
/// Режим выборки элементов /// Режим выборки элементов
/// </summary> /// </summary>

View File

@ -1,19 +1,41 @@
using AsbCloudApp.Data.Subsystems; using AsbCloudApp.Data.Subsystems;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AsbCloudApp.Services.Subsystems namespace AsbCloudApp.Services.Subsystems
{ {
#nullable enable #nullable enable
/// <summary>
/// Получение инфо о наработке подсистем
/// </summary>
public interface ISubsystemOperationTimeService public interface ISubsystemOperationTimeService
{ {
/// <summary>
/// Статистика о наработке подсистем
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<SubsystemStatDto>?> GetStatAsync(SubsystemOperationTimeRequest request, CancellationToken token); Task<IEnumerable<SubsystemStatDto>?> GetStatAsync(SubsystemOperationTimeRequest request, CancellationToken token);
/// <summary>
/// Удаление наработки по подсистемам.
/// Если удаляется конец, то фоновый сервис подсчета наработки восстановит эти данные.
/// Может потребоваться для запуска повторного расчета по новому алгоритму.
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> DeleteAsync(SubsystemOperationTimeRequest request, CancellationToken token); Task<int> DeleteAsync(SubsystemOperationTimeRequest request, CancellationToken token);
/// <summary>
/// Интервалы работы подсистем
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<SubsystemOperationTimeDto>?> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token); Task<IEnumerable<SubsystemOperationTimeDto>?> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token);
} }
#nullable disable #nullable disable

View File

@ -1,7 +1,4 @@
using System; using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
@ -9,9 +6,8 @@ namespace AsbCloudDb.Model.Subsystems
{ {
[Table("t_subsystem"), Comment("Описание подсистем")] [Table("t_subsystem"), Comment("Описание подсистем")]
public class Subsystem : IId public class Subsystem : IId
{ {
[Key] [Column("id"), Key]
[Column("id")]
public int Id { get; set; } public int Id { get; set; }
[Column("name")] [Column("name")]
@ -22,6 +18,5 @@ namespace AsbCloudDb.Model.Subsystems
[StringLength(255)] [StringLength(255)]
public string? Description { get; set; } public string? Description { get; set; }
} }
} }

View File

@ -9,8 +9,7 @@ namespace AsbCloudDb.Model.Subsystems
[Table("t_subsystem_operation_time"), Comment("наработки подсистем")] [Table("t_subsystem_operation_time"), Comment("наработки подсистем")]
public partial class SubsystemOperationTime : IId public partial class SubsystemOperationTime : IId
{ {
[Key] [Column("id"), Key]
[Column("id")]
public int Id { get; set; } public int Id { get; set; }
[Column("id_telemetry"), Comment("ИД телеметрии по которой выдается информация")] [Column("id_telemetry"), Comment("ИД телеметрии по которой выдается информация")]
@ -20,23 +19,23 @@ namespace AsbCloudDb.Model.Subsystems
public int IdSubsystem { get; set; } public int IdSubsystem { get; set; }
[Column("date_start"), Comment("дата/время включения подсистемы")] [Column("date_start"), Comment("дата/время включения подсистемы")]
public DateTimeOffset DateStart { get; set; } public DateTimeOffset DateStart { get; set; }
[Column("date_end"), Comment("дата/время выключения подсистемы")] [Column("date_end"), Comment("дата/время выключения подсистемы")]
public DateTimeOffset DateEnd { get; set; } public DateTimeOffset DateEnd { get; set; }
[Column("depth_start"), Comment("глубина забоя на момент включения подсистемы")] [Column("depth_start"), Comment("глубина забоя на момент включения подсистемы")]
public float? DepthStart { get; set; } public float? DepthStart { get; set; }
[Column("depth_end"), Comment("глубина забоя на момент выключения подсистемы")] [Column("depth_end"), Comment("глубина забоя на момент выключения подсистемы")]
public float? DepthEnd { get; set; } public float? DepthEnd { get; set; }
[JsonIgnore] [JsonIgnore]
[ForeignKey(nameof(IdSubsystem))] [ForeignKey(nameof(IdSubsystem))]
public virtual Subsystem Subsystem { get; set; } public virtual Subsystem Subsystem { get; set; } = null!;
[JsonIgnore] [JsonIgnore]
[ForeignKey(nameof(IdTelemetry))] [ForeignKey(nameof(IdTelemetry))]
public virtual Telemetry Telemetry { get; set; } public virtual Telemetry Telemetry { get; set; } = null!;
} }
} }

View File

@ -7,7 +7,6 @@ using Npgsql;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Data.SqlClient;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -26,17 +25,18 @@ namespace AsbCloudInfrastructure.Services.Subsystems
{ {
connectionString = configuration.GetConnectionString("DefaultConnection"); connectionString = configuration.GetConnectionString("DefaultConnection");
} }
protected override async Task ExecuteAsync(CancellationToken token) protected override async Task ExecuteAsync(CancellationToken token)
{ {
var timeToStartAnalysis = DateTime.Now; var timeToStart = DateTime.Now;
var options = new DbContextOptionsBuilder<AsbCloudDbContext>() var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
.UseNpgsql(connectionString) .UseNpgsql(connectionString)
.Options; .Options;
while (!token.IsCancellationRequested) while (!token.IsCancellationRequested)
{ {
if (DateTime.Now > timeToStartAnalysis) if (DateTime.Now > timeToStart)
{ {
timeToStartAnalysis = DateTime.Now + period; timeToStart = DateTime.Now + period;
try try
{ {
using var context = new AsbCloudDbContext(options); using var context = new AsbCloudDbContext(options);
@ -49,7 +49,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems
} }
GC.Collect(); GC.Collect();
} }
var ms = (int)(timeToStartAnalysis - DateTime.Now).TotalMilliseconds; var ms = (int)(timeToStart - DateTime.Now).TotalMilliseconds;
ms = ms > 100 ? ms : 100; ms = ms > 100 ? ms : 100;
await Task.Delay(ms, token).ConfigureAwait(false); await Task.Delay(ms, token).ConfigureAwait(false);
} }
@ -76,7 +76,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems
.Select(t => t.Id) .Select(t => t.Id)
.ToListAsync(token); .ToListAsync(token);
var JounedlastDetectedDates = telemetryIds var telemetryLastDetectedDates = telemetryIds
.GroupJoin(lastDetectedDates, .GroupJoin(lastDetectedDates,
t => t, t => t,
o => o.IdTelemetry, o => o.IdTelemetry,
@ -85,8 +85,9 @@ namespace AsbCloudInfrastructure.Services.Subsystems
IdTelemetry = outer, IdTelemetry = outer,
inner.SingleOrDefault()?.LastDate, inner.SingleOrDefault()?.LastDate,
}); });
var affected = 0; 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); var newOperationsSaub = await OperationTimeSaubAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
if (newOperationsSaub?.Any() == true) if (newOperationsSaub?.Any() == true)
@ -103,139 +104,157 @@ namespace AsbCloudInfrastructure.Services.Subsystems
} }
return affected; return affected;
} }
private static async Task<IEnumerable<SubsystemOperationTime>?> OperationTimeSaubAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token) private static async Task<IEnumerable<SubsystemOperationTime>> OperationTimeSaubAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
{ {
var operationTimeSaub = static int? GetSubsytemId(short mode)
$"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<SubsystemsSpinWithDepth>();
if (result.HasRows)
{ {
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<SubsystemOperationTime>(32);
if (result.Read())
{
var mode = result.GetFieldValue<short>(1);
var idSubsystem = GetSubsytemId(mode);
var dateStart = result.GetFieldValue<DateTimeOffset>(0);
var depthStart = result.GetFieldValue<float>(2);
while (result.Read()) while (result.Read())
{ {
var itemEntity = new SubsystemsSpinWithDepth() var dateEnd = result.GetFieldValue<DateTimeOffset>(0);
var depthEnd = result.GetFieldValue<float>(2);
if (idSubsystem.HasValue)
{ {
Date = result.GetFieldValue<DateTimeOffset>(0), var operationTimeItem = new SubsystemOperationTime()
IdSubsystem = result.GetFieldValue<short>(1)+1, {
Depth = result.GetFieldValue<float>(2) IdTelemetry = idTelemetry,
}; IdSubsystem = idSubsystem.Value,
telemetryOpearationSaubSubsystems.Add(itemEntity); DateStart = dateStart,
DateEnd = dateEnd,
DepthStart = depthStart,
DepthEnd = depthEnd
};
subsystemOperationTime.Add(operationTimeItem);
}
mode = result.GetFieldValue<short>(1);
idSubsystem = GetSubsytemId(mode);
dateStart = dateEnd;
depthStart = depthEnd;
} }
} }
var resultSubsystemOperationTime = new List<SubsystemOperationTime>(); return subsystemOperationTime;
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;
} }
private static async Task<IEnumerable<SubsystemOperationTime>?> OperationTimeSpinAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token) private static async Task<IEnumerable<SubsystemOperationTime>?> OperationTimeSpinAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
{ {
Predicate<int> isSubsystemTorqueState = (int state) => state == 7; static int? GetSubsytemId(short mode, int state)
Predicate<short> isSubsystemTorqueMode = (short mode) => (mode & 2) > 0;
Predicate<int> 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<SubsystemsSpinWithDepth>();
if (result.HasRows)
{ {
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<SubsystemOperationTime>(32);
if (result.Read())
{
var mode = result.GetFieldValue<short>(1);
var state = result.GetFieldValue<int>(2);
var idSubsystem = GetSubsytemId(mode, state);
var dateStart = result.GetFieldValue<DateTimeOffset>(0);
var depthStart = result.GetFieldValue<float?>(3);
while (result.Read()) while (result.Read())
{ {
var itemEntity = new SubsystemsSpinWithDepth() var dateEnd = result.GetFieldValue<DateTimeOffset>(0);
var depthEnd = result.GetFieldValue<float?>(3);
if (idSubsystem.HasValue)
{ {
Date = result.GetFieldValue<DateTimeOffset>(0), var operationTimeItem = new SubsystemOperationTime()
Mode = result.GetFieldValue<short>(1), {
State = result.GetFieldValue<int>(2), IdTelemetry = idTelemetry,
Depth = result.GetFieldValue<float>(3) IdSubsystem = idSubsystem.Value,
}; DateStart = dateStart,
int? subsystemId = isSubsystemTorqueState(itemEntity.State) && isSubsystemTorqueMode(itemEntity.Mode) DateEnd = dateEnd,
? idSubsytemTorqueMaster DepthStart = depthStart,
: isSubsystemSpin(itemEntity.State) DepthEnd = depthEnd
? idSubsytemSpinMaster };
: 0; subsystemOperationTime.Add(operationTimeItem);
if (subsystemId.HasValue)
{
itemEntity.IdSubsystem = subsystemId.Value;
telemetryOpearationSpinSubsystems.Add(itemEntity);
} }
mode = result.GetFieldValue<short>(1);
state = result.GetFieldValue<int>(2);
idSubsystem = GetSubsytemId(mode, state);
dateStart = dateEnd;
depthStart = depthEnd;
} }
} }
var resultSubsystemOperationTime = new List<SubsystemOperationTime>(); return subsystemOperationTime;
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;
} }
} }
#nullable disable #nullable disable

View File

@ -29,6 +29,8 @@ namespace AsbCloudInfrastructure.Services.Subsystems
this.wellService = wellService; this.wellService = wellService;
this.subsystemService = subsystemService; this.subsystemService = subsystemService;
} }
/// <inheritdoc/>
public async Task<int> DeleteAsync(SubsystemOperationTimeRequest request, CancellationToken token) public async Task<int> DeleteAsync(SubsystemOperationTimeRequest request, CancellationToken token)
{ {
var well = await wellService.GetOrDefaultAsync(request.IdWell, token); var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
@ -41,39 +43,40 @@ namespace AsbCloudInfrastructure.Services.Subsystems
return await db.SaveChangesAsync(token); return await db.SaveChangesAsync(token);
} }
/// <inheritdoc/>
public async Task<IEnumerable<SubsystemOperationTimeDto>?> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token) public async Task<IEnumerable<SubsystemOperationTimeDto>?> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token)
{ {
var well = await wellService.GetOrDefaultAsync(request.IdWell, token); var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
if (well?.IdTelemetry is null || well.Timezone is null) if (well?.IdTelemetry is null || well.Timezone is null)
return null; return null;
var query = BuildQuery(request); var query = BuildQuery(request);
if (query is null) if (query is null)
return null; return null;
IEnumerable<SubsystemOperationTime> data = await query.ToListAsync(token);
if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeInner) if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeInner)
{ {
if (request.GtDate is not null) 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) 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) else if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeTrim)
{ {
if (!request.GtDate.HasValue) var begin = request.GtDate?.ToUtcDateTimeOffset(well.Timezone.Hours);
throw new ArgumentNullException(nameof(request.GtDate)); var end = request.LtDate?.ToUtcDateTimeOffset(well.Timezone.Hours);
var begin = request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); data = Trim(data, begin, end);
if (!request.LtDate.HasValue)
throw new ArgumentNullException(nameof(request.LtDate));
var end = request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours);
IEnumerable<SubsystemOperationTime>? data = query.ToList();
data = Trim(data, begin, end);
if (data is not null)
return data.Select(o => Convert(o, well));
return null;
} }
var dtos = query.Select(o => Convert(o, well));
var dtos = data.Select(o => Convert(o, well));
return dtos; return dtos;
} }
/// <inheritdoc/>
public async Task<IEnumerable<SubsystemStatDto>?> GetStatAsync(SubsystemOperationTimeRequest request, CancellationToken token) public async Task<IEnumerable<SubsystemStatDto>?> GetStatAsync(SubsystemOperationTimeRequest request, CancellationToken token)
{ {
request.SelectMode = SubsystemOperationTimeRequest.SelectModeTrim; request.SelectMode = SubsystemOperationTimeRequest.SelectModeTrim;
@ -83,110 +86,104 @@ namespace AsbCloudInfrastructure.Services.Subsystems
var statList = CalcStat(data, request); var statList = CalcStat(data, request);
return statList; return statList;
} }
private IEnumerable<SubsystemOperationTime>? Trim(IEnumerable<SubsystemOperationTime>? data, DateTimeOffset gtDate, DateTimeOffset ltDate)
private static IEnumerable<SubsystemOperationTime> Trim(IEnumerable<SubsystemOperationTime> data, DateTimeOffset? gtDate, DateTimeOffset? ltDate)
{ {
if (data is null) var items = data.Select((item) =>
return null; {
var ItemsNormal = data.Where(q => if (gtDate.HasValue && item.DateStart < gtDate.Value)
(q.DateStart >= gtDate) && (q.DateEnd <= ltDate)).ToList();
var itemsToTrim = data.Where(q =>
q.DateStart < gtDate || ltDate < q.DateEnd)
.Select(o => new SubsystemOperationTime
{ {
Id = o.Id, item.DateStart = gtDate.Value;
DateStart = gtDate < o.DateStart ? o.DateStart : gtDate, item.DepthStart = null;
DateEnd = ltDate > o.DateEnd ? o.DateEnd : ltDate, }
IdSubsystem = o.IdSubsystem, if (ltDate.HasValue && item.DateEnd > ltDate.Value)
IdTelemetry = o.IdTelemetry, {
DepthStart = gtDate > o.DateEnd ? o.DepthStart : null, item.DateEnd = ltDate.Value;
DepthEnd = ltDate < o.DateStart ? o.DepthEnd : null, item.DepthEnd = null;
Subsystem = o.Subsystem, }
Telemetry = o.Telemetry return item;
}) });
.ToList();
ItemsNormal.AddRange(itemsToTrim); return items;
return ItemsNormal.OrderBy(o => o.DateStart).ToList();
} }
private IEnumerable<SubsystemStatDto> CalcStat(IEnumerable<SubsystemOperationTimeDto> listOperationTimeSubsystems, SubsystemOperationTimeRequest request)
private IEnumerable<SubsystemStatDto> CalcStat(IEnumerable<SubsystemOperationTimeDto> dtos, SubsystemOperationTimeRequest request)
{ {
var result = new List<SubsystemStatDto>(); var groupedDataSubsystems = dtos
var groupedDataSubsystems = listOperationTimeSubsystems .GroupBy(o => o.IdSubsystem);
.GroupBy(x => x.IdSubsystem);
var periodGroupTotal = groupedDataSubsystems var periodGroupTotal = dtos.Sum(o => (o.DateEnd - o.DateStart).TotalHours);
.Sum(g => g.Sum(o=> (o.DateEnd - o.DateStart).TotalHours));
var gtDate = request.GtDate ?? listOperationTimeSubsystems.Min(d => d.DateStart); var gtDate = request.GtDate ?? dtos.Min(o => o.DateStart);
var ltDate = request.LtDate ?? listOperationTimeSubsystems.Max(d => d.DateEnd); var ltDate = request.LtDate ?? dtos.Max(o => o.DateEnd);
var periodRequest = listOperationTimeSubsystems
.Sum(o => (o.DateEnd - o.DateStart).TotalHours); var periodRequest = (ltDate - gtDate).TotalHours;
foreach (var item in groupedDataSubsystems)
{ var result = groupedDataSubsystems.Select(item =>
var periodGroup = item.Sum(g => (g.DateEnd - g.DateStart).TotalHours); {
int idSubsystem = item.First().IdSubsystem; var periodGroup = item.Sum(o => (o.DateEnd - o.DateStart).TotalHours);
var subsystemStat = new SubsystemStatDto() var subsystemStat = new SubsystemStatDto()
{ {
IdSubsystem = idSubsystem, IdSubsystem = item.Key,
SubsystemName = subsystemService.GetOrDefault(idSubsystem)?.Name ?? "unknown", SubsystemName = subsystemService.GetOrDefault(item.Key)?.Name ?? "unknown",
UsedTimeHours =periodGroup, UsedTimeHours = periodGroup,
KUsage = 1d*periodGroup / periodRequest, KUsage = 1d * periodGroup / periodRequest,
K2 = 1d*periodGroup / periodGroupTotal, K2 = 1d * periodGroup / periodGroupTotal,
}; };
result.Add(subsystemStat); return subsystemStat;
} });
return result; return result;
} }
private IQueryable<SubsystemOperationTime>? BuildQuery(SubsystemOperationTimeRequest request) private IQueryable<SubsystemOperationTime>? BuildQuery(SubsystemOperationTimeRequest request)
{ {
if (request.SelectMode > 0 && request.GtDate is null && request.LtDate is null)
return null;
var well = wellService.GetOrDefault(request.IdWell); var well = wellService.GetOrDefault(request.IdWell);
if (well?.IdTelemetry is null || well.Timezone is null) if (well?.IdTelemetry is null || well.Timezone is null)
return null; return null;
var query = db.SubsystemOperationTimes var query = db.SubsystemOperationTimes
.Include(o => o.Subsystem) .Include(o => o.Subsystem)
.Where(o => o.IdTelemetry == well.IdTelemetry); .Where(o => o.IdTelemetry == well.IdTelemetry)
DateTimeOffset gtDateWellTime; .AsNoTracking();
DateTimeOffset ltDateWellTime;
if (request.IdsSubsystems?.Any() == true) if (request.IdsSubsystems?.Any() == true)
query = query.Where(o => request.IdsSubsystems.Contains(o.IdSubsystem)); 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); DateTimeOffset gtDate = request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours);
ltDateWellTime = request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); query = query.Where(o => o.DateEnd >= gtDate);
//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);
} }
else if (request.LtDate is not null) if (request.LtDate.HasValue)
{ {
ltDateWellTime = request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours); DateTimeOffset ltDate = request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours);
query = query.Where(o => o.DateEnd <= ltDateWellTime); 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) if (request.GtDepth.HasValue)
query = query.Where(o => o.DepthEnd <= request.LtDepth.Value); 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) if (request?.SortFields?.Any() == true)
{ {
query = query.SortBy(request.SortFields); query = query.SortBy(request.SortFields);
} }
else else
{
query = query query = query
.OrderBy(o => o.DateStart) .OrderBy(o => o.DateStart)
.ThenBy(o => o.DepthStart); .ThenBy(o => o.DepthStart);
}
if (request?.Skip > 0) if (request?.Skip > 0)
query = query.Skip((int)request.Skip); query = query.Skip((int)request.Skip);
@ -198,7 +195,8 @@ namespace AsbCloudInfrastructure.Services.Subsystems
return query; return query;
} }
private SubsystemOperationTimeDto Convert(SubsystemOperationTime operationTime, WellDto well)
private static SubsystemOperationTimeDto Convert(SubsystemOperationTime operationTime, WellDto well)
{ {
var dto = operationTime.Adapt<SubsystemOperationTimeDto>(); var dto = operationTime.Adapt<SubsystemOperationTimeDto>();
dto.DateStart = operationTime.DateStart.ToRemoteDateTime(well.Timezone.Hours); dto.DateStart = operationTime.DateStart.ToRemoteDateTime(well.Timezone.Hours);

View File

@ -27,21 +27,17 @@ namespace AsbCloudInfrastructure.Services.Subsystems
var well = await wellService.GetOrDefaultAsync(idWell, token); var well = await wellService.GetOrDefaultAsync(idWell, token);
if (well?.IdTelemetry is null || well.Timezone is null) if (well?.IdTelemetry is null || well.Timezone is null)
return null; return null;
var wellSubsystem = await dbContext.SubsystemOperationTimes var entities = await dbContext.SubsystemOperationTimes
.Include(e => e.Subsystem) .Include(e => e.Subsystem)
.AsNoTracking() .AsNoTracking()
.Where(o => o.IdTelemetry == well.IdTelemetry) .Where(o => o.IdTelemetry == well.IdTelemetry)
.DistinctBy(o => o.IdSubsystem) .Select(o => o.Subsystem)
.Select(d => Convert( new () .Distinct()
{ .ToArrayAsync(token);
Id = d.Subsystem.Id, var dtos = entities.Select(e => e.Adapt<SubsystemDto>());
Name = d.Subsystem.Name, return dtos;
Description = d.Subsystem.Description,
}))
.ToListAsync(token);
return wellSubsystem;
} }
public async Task<IEnumerable<SubsystemDto>?> GetSubsystemAsync(int? idWell, CancellationToken token) public async Task<IEnumerable<SubsystemDto>?> GetSubsystemAsync(int? idWell, CancellationToken token)
{ {
if (idWell.HasValue) if (idWell.HasValue)
@ -52,11 +48,6 @@ namespace AsbCloudInfrastructure.Services.Subsystems
var subsystem = await GetAllAsync(token); var subsystem = await GetAllAsync(token);
return subsystem; return subsystem;
} }
new private static SubsystemDto Convert(Subsystem subsystem)
{
var dto = subsystem.Adapt<SubsystemDto>();
return dto;
}
} }
#nullable disable #nullable disable
} }

View File

@ -19,5 +19,5 @@ namespace AsbCloudWebApi.Controllers.Subsystems
{ {
} }
} }
} }

View File

@ -21,13 +21,11 @@ namespace AsbCloudWebApi.Controllers.Subsystems
{ {
private readonly ISubsystemOperationTimeService subsystemOperationTimeService; private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
private readonly IWellService wellService; private readonly IWellService wellService;
private readonly ICrudService<SubsystemDto> subsystemServiceCrud;
private readonly ISubsystemService subsystemService; private readonly ISubsystemService subsystemService;
public SubsystemOperationTimeController(ISubsystemOperationTimeService subsystemOperationTimeService, IWellService wellService, ICrudService<SubsystemDto> subsystemServiceCrud, ISubsystemService subsystemService) public SubsystemOperationTimeController(ISubsystemOperationTimeService subsystemOperationTimeService, IWellService wellService, ISubsystemService subsystemService)
{ {
this.subsystemOperationTimeService = subsystemOperationTimeService; this.subsystemOperationTimeService = subsystemOperationTimeService;
this.wellService = wellService; this.wellService = wellService;
this.subsystemServiceCrud = subsystemServiceCrud;
this.subsystemService = subsystemService; this.subsystemService = subsystemService;
} }
/// <summary> /// <summary>
@ -53,8 +51,8 @@ namespace AsbCloudWebApi.Controllers.Subsystems
if (idWell.HasValue) if (idWell.HasValue)
if (!await UserHasAccesToWellAsync(idWell.Value, token)) if (!await UserHasAccesToWellAsync(idWell.Value, token))
return Forbid(); return Forbid();
var result = await subsystemService.GetSubsystemAsync(idWell, token); var result = await subsystemService.GetSubsystemAsync(idWell, token);
return Ok(result); return Ok(result);
} }
/// <summary> /// <summary>