Merge pull request 'dev' (#242) from dev into master

Reviewed-on: http://test.digitaldrilling.ru:8080/DDrilling/AsbCloudServer/pulls/242
This commit is contained in:
Никита Фролов 2024-03-26 19:24:52 +05:00
commit a00b8caab0
231 changed files with 46842 additions and 5418 deletions

View File

@ -14,7 +14,7 @@ jobs:
if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x
dotnet-version: 8.0.x
- name: Check out repository code
uses: actions/checkout@v4
- name: Add gitea as nuget source

View File

@ -14,7 +14,7 @@ jobs:
if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x
dotnet-version: 8.0.x
- name: Check out repository code
uses: actions/checkout@v4
- name: Add gitea as nuget source

View File

@ -14,7 +14,7 @@ jobs:
if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x
dotnet-version: 8.0.x
- name: Check out repository code
uses: actions/checkout@v4
- name: Add gitea as nuget source

View File

@ -13,7 +13,7 @@ jobs:
if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x
dotnet-version: 8.0.x
- name: Check out repository code
uses: actions/checkout@v4
- name: Add gitea as nuget source

View File

@ -1,19 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq" Version="4.3.0" />
</ItemGroup>
<ItemGroup>
<None Remove="Data\DailyReport\" />
</ItemGroup>
<ItemGroup>
<EditorConfigFiles Remove="D:\Source\AsbCloudApp\Services\.editorconfig" />
</ItemGroup>

View File

@ -1,7 +1,4 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using AsbCloudApp.Data.User;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data
{

View File

@ -0,0 +1,132 @@
using System;
namespace AsbCloudApp.Data
{
public class DataSaubStatDto:IId
{
/// <summary>
///
/// </summary>
public int Id { get; set; }
/// <summary>
/// Дата и время начала
/// </summary>
public DateTimeOffset DateStart { get; set; }
/// <summary>
/// Дата и время окончания
/// </summary>
public DateTimeOffset DateEnd { get; set; }
/// <summary>
/// Глубина забоя по стволу начальная
/// </summary>
public double DepthStart { get; set; }
/// <summary>
/// Глубина забоя по стволу конечная
/// </summary>
public double DepthEnd { get; set; }
/// <summary>
/// Скорость бурения
/// </summary>
public double Speed { get; set; }
/// <summary>
/// Ограничение скорости блока
/// </summary>
public double? BlockSpeedSp { get; set; }
/// <summary>
/// Давление
/// </summary>
public double Pressure { get; set; }
/// <summary>
/// Давление холостого хода
/// </summary>
public double? PressureIdle { get; set; }
/// <summary>
/// Ограничение фактического давления
/// </summary>
public double? PressureSp { get; set; }
/// <summary>
/// Фактическая нагрузка
/// </summary>
public double AxialLoad { get; set; }
/// <summary>
/// Ограничение факт. нагрузки
/// </summary>
public double? AxialLoadSp { get; set; }
/// <summary>
/// Максимально допустимая нагрузка
/// </summary>
public double? AxialLoadLimitMax { get; set; }
/// <summary>
/// Фактический момент
/// </summary>
public double RotorTorque { get; set; }
/// <summary>
/// Ограничение факт. момента
/// </summary>
public double? RotorTorqueSp { get; set; }
/// <summary>
/// Максимально допустимый момент
/// </summary>
public double? RotorTorqueLimitMax { get; set; }
/// <summary>
/// Работа при достижении ограничения
/// </summary>
public short? IdFeedRegulator { get; set; }
/// <summary>
/// Фактическая скорость оборотов ВСП
/// </summary>
public double RotorSpeed { get; set; }
/// <summary>
/// Название автоопределённой операции
/// </summary>
public int IdCategory { get; set; }
/// <summary>
/// Флаги подсистем
/// </summary>
public int EnabledSubsystems { get; set; }
/// <summary>
/// Наличие или отсутствие осцилляции
/// </summary>
public bool HasOscillation { get; set; }
/// <summary>
/// Фактический расход
/// </summary>
public double Flow { get; set; }
/// <summary>
/// Ключ телеметрии
/// </summary>
public int IdTelemetry { get; set; }
/// <summary>
/// Телеметрия
/// </summary>
public TelemetryDto Telemetry { get; set; } = null!;
/// <summary>
/// Категория автоопределенной операции
/// </summary>
public WellOperationCategoryDto OperationCategory { get; set; } = null!;
}
}

View File

@ -1,100 +1,91 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data.DetectedOperation
namespace AsbCloudApp.Data.DetectedOperation;
/// <summary>
/// Автоматически определенная операция
/// </summary>
public class DetectedOperationDto: IId
{
/// <inheritdoc/>
[Required]
public int Id { get; set; }
/// <summary>
/// Автоматически определяемая операция
/// Id телеметрии
/// </summary>
public class DetectedOperationDto : IId, IWellRelated
{
/// <inheritdoc/>
[Required]
public int Id { get; set; }
[Required]
public int IdTelemetry { get; set; }
/// <inheritdoc/>
[Required]
public int IdWell { get; set; }
/// <summary>
/// Id названия/описания операции
/// </summary>
[Required]
public int IdCategory { get; set; }
/// <summary>
/// Id телеметрии
/// </summary>
[Required]
public int IdTelemetry { get; set; }
/// <summary>
/// Id пользователя панели на момент начала операции
/// </summary>
[Required]
public int IdUserAtStart { get; set; }
/// <summary>
/// Пользователь панели оператора
/// </summary>
public string? TelemetryUserName { get; set; }
/// <summary>
/// Id названия/описания операции
/// </summary>
[Required]
public int IdCategory { get; set; }
/// <summary>
/// Дата завершения операции в часовом поясе скважины
/// </summary>
[Required]
public DateTimeOffset DateEnd { get; set; }
/// <summary>
/// Id пользователя панели
/// </summary>
[Required]
public int IdUsersAtStart { get; set; }
/// <summary>
/// Дата начала операции в часовом поясе скважины
/// </summary>
[Required]
public DateTimeOffset DateStart { get; set; }
/// <summary>
/// Дата начала операции в часовом поясе скважины
/// </summary>
[Required]
public DateTime DateStart { get; set; }
/// <summary>
/// глубина на завершения операции, м
/// </summary>
[Required]
public double DepthEnd { get; set; }
/// <summary>
/// Дата завершения операции в часовом поясе скважины
/// </summary>
[Required]
public DateTime DateEnd { get; set; }
/// <summary>
/// глубина на начало операции, м
/// </summary>
[Required]
public double DepthStart { get; set; }
/// <summary>
/// Продолжительность операции в минутах
/// </summary>
[Required]
public double DurationMinutes => (DateEnd - DateStart).TotalMinutes;
/// <summary>
/// Продолжительность операции в минутах
/// </summary>
[Required]
public double DurationMinutes => (DateEnd - DateStart).TotalMinutes;
/// <summary>
/// глубина на начало операции, м
/// </summary>
[Required]
public double DepthStart { get; set; }
/// <summary>
/// Флаг включенной подсистемы
/// </summary>
[Required]
public int EnabledSubsystems { get; set; }
/// <summary>
/// глубина на завершения операции, м
/// </summary>
[Required]
public double DepthEnd { get; set; }
/// <summary>
/// название/описание операции
/// </summary>
[Required]
public WellOperationCategoryDto OperationCategory { get; set; } = null!;
/// <summary>
/// название/описание операции
/// </summary>
[Required]
public WellOperationCategoryDto OperationCategory { get; set; } = null!;
/// <summary>
/// Ключевой параметр операции
/// </summary>
[Required]
public double Value { get; set; }
/// <summary>
/// Пользователь панели оператора
/// </summary>
public string? TelemetryUserName { get; set; }
/// <summary>
/// Бурильщик
/// </summary>
public DrillerDto? Driller { get; set; }
/// <summary>
/// Целевые/нормативные показатели
/// </summary>
public OperationValueDto? OperationValue { get; set; }
/// <summary>
/// Ключевой параметр операции
/// </summary>
[Required]
public double Value { get; set; }
/// <summary>
/// Флаг включенной подсистемы
/// </summary>
[Required]
public int EnabledSubsystems { get; set; }
}
}
/// <summary>
/// Доп. инфо по операции
/// </summary>
public IDictionary<string, object> ExtraData { get; set; } = new Dictionary<string, object>();
}

View File

@ -13,7 +13,7 @@ namespace AsbCloudApp.Data.DetectedOperation
/// Список всех операций
/// </summary>
[Required]
public IEnumerable<DetectedOperationDto> Operations { get; set; } = Enumerable.Empty<DetectedOperationDto>();
public IEnumerable<DetectedOperationWithDrillerDto> Operations { get; set; } = Enumerable.Empty<DetectedOperationWithDrillerDto>();
/// <summary>
/// Статистика по бурильщикам

View File

@ -0,0 +1,18 @@
namespace AsbCloudApp.Data.DetectedOperation
{
/// <summary>
/// Автоматически определяемая операция
/// </summary>
public class DetectedOperationWithDrillerDto : DetectedOperationDto
{
/// <summary>
/// Бурильщик
/// </summary>
public DrillerDto? Driller { get; set; }
/// <summary>
/// Целевые/нормативные показатели
/// </summary>
public OperationValueDto? OperationValue { get; set; }
}
}

View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
using AsbCloudApp.Data.Subsystems;
namespace AsbCloudApp.Data;
/// <summary>
/// ñòàòèñòèêà íàðàáîòêè ïî áóðèëüùèêàì
/// </summary>
public class DrillerDetectedOperationStatDto
{
/// <summary>
/// Ñòàòèñòèêè ïîäñèñòåì
/// </summary>
public IEnumerable<SubsystemStatDto> Statistic { get; set; } = null!;
/// <summary>
/// Ðàñïèñàíèå áóðèëüùèêà
/// </summary>
public ScheduleDto Schedule { get; set; } = null!;
/// <summary>
/// Ñêâàæèíà
/// </summary>
public WellDto Well { get; set; } = null!;
}

View File

@ -8,6 +8,30 @@ namespace AsbCloudApp.Data
/// </summary>
public class LimitingParameterDto
{
/// <summary>
/// Нет ограничения
/// </summary>
public const int NoLimit = 0;
/// <summary>
/// МСП
/// </summary>
public const int RopPlan = 1;
/// <summary>
/// Давление
/// </summary>
public const int Pressure = 2;
/// <summary>
/// Осевая нагрузка
/// </summary>
public const int AxialLoad = 3;
/// <summary>
/// Момент
/// </summary>
public const int RotorTorque = 4;
/// <summary>
/// Идентификатор скважины
/// </summary>

View File

@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace AsbCloudApp.Data;
/// <summary>
/// Результат парсинга файла
/// </summary>
/// <typeparam name="TDto"></typeparam>
public class ParserResultDto<TDto> : ValidationResultDto<IEnumerable<ValidationResultDto<TDto>>>
where TDto : class, IId
{
}

View File

@ -1,46 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data.ProcessMapPlan;
/// <inheritdoc/>
public abstract class ProcessMapPlanBaseDto : ChangeLogAbstract, IId, IWellRelated, IValidatableObject
{
/// <summary>
/// Id скважины
/// </summary>
[Range(1, int.MaxValue, ErrorMessage = "Id скважины не может быть меньше 1")]
public int IdWell { get; set; }
/// <summary>
/// Тип секции
/// </summary>
[Range(1, int.MaxValue, ErrorMessage = "Id секции скважины не может быть меньше 1")]
public int IdWellSectionType { get; set; }
/// <summary>
/// Глубина по стволу от, м
/// <para>
/// на начало интервала
/// </para>
/// </summary>
[Range(0, 99999.9, ErrorMessage = "Глубина не может быть отрицательной")]
public double DepthStart { get; set; }
/// <summary>
/// Глубина по стволу до, м
/// <para>
/// на конец интервала
/// </para>
/// </summary>
[Range(0, 99999.9, ErrorMessage = "Глубина не может быть отрицательной")]
public double DepthEnd { get; set; }
/// <inheritdoc/>
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(DepthEnd <= DepthStart)
yield return new ("глубина окончания должна быть больше глубины начала", new string[] {nameof(DepthEnd), nameof(DepthStart) });
}
}

View File

@ -1,38 +1,27 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data.ProcessMaps;
/// <inheritdoc/>
public abstract class ProcessMapPlanBaseDto : IId, IWellRelated
public abstract class ProcessMapPlanBaseDto : ChangeLogAbstract, IId, IWellRelated, IValidatableObject
{
/// <inheritdoc/>
[Required]
public int Id { get; set; }
/// <summary>
/// Id скважины
/// </summary>
[Required]
[Range(1, int.MaxValue, ErrorMessage = "Id скважины не может быть меньше 1")]
public int IdWell { get; set; }
/// <summary>
/// Id пользователя
/// </summary>
public int IdUser { get; set; }
/// <summary>
/// Тип секции
/// </summary>
[Required]
[Range(1, int.MaxValue, ErrorMessage = "Id секции скважины не может быть меньше 1")]
public int IdWellSectionType { get; set; }
/// <summary>
/// Дата последнего изменения
/// Название секции
/// </summary>
public DateTimeOffset LastUpdate { get; set; }
public string? Section { get; set; }
/// <summary>
/// Глубина по стволу от, м
@ -40,7 +29,6 @@ public abstract class ProcessMapPlanBaseDto : IId, IWellRelated
/// на начало интервала
/// </para>
/// </summary>
[Required]
[Range(0, 99999.9, ErrorMessage = "Глубина не может быть отрицательной")]
public double DepthStart { get; set; }
@ -50,12 +38,13 @@ public abstract class ProcessMapPlanBaseDto : IId, IWellRelated
/// на конец интервала
/// </para>
/// </summary>
[Required]
[Range(0, 99999.9, ErrorMessage = "Глубина не может быть отрицательной")]
public double DepthEnd { get; set; }
/// <summary>
/// Комментарий
/// </summary>
public string? Comment { get; set; }
/// <inheritdoc/>
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (DepthEnd <= DepthStart)
yield return new("Глубина окончания должна быть больше глубины начала", new string[] { nameof(DepthEnd), nameof(DepthStart) });
}
}

View File

@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data.ProcessMapPlan;
namespace AsbCloudApp.Data.ProcessMaps;
/// <summary>
/// РТК план бурение скважины
@ -13,6 +13,11 @@ public class ProcessMapPlanDrillingDto : ProcessMapPlanBaseDto
[Range(1, 2, ErrorMessage = "Id режима должен быть либо 1-ротор либо 2-слайд")]
public int IdMode { get; set; }
/// <summary>
/// Название режима бурения
/// </summary>
public string? Mode { get; set; }
/// <summary>
/// Осевая нагрузка, т план
/// </summary>
@ -28,43 +33,43 @@ public class ProcessMapPlanDrillingDto : ProcessMapPlanBaseDto
/// <summary>
/// Перепад давления, атм план
/// </summary>
[Range(0, 99999.9, ErrorMessage = "Перепад давления, атм должна быть в пределах от 0 до 99999.9")]
[Range(0, 99999.9, ErrorMessage = "Перепад давления, атм должна быть в пределах от 0 до 99999.9")]
public double DeltaPressurePlan { get; set; }
/// <summary>
/// Перепад давления, атм ограничение
/// </summary>
[Range(0, 99999.9, ErrorMessage = "Перепад давления, атм должна быть в пределах от 0 до 99999.9")]
[Range(0, 99999.9, ErrorMessage = "Перепад давления, атм должна быть в пределах от 0 до 99999.9")]
public double DeltaPressureLimitMax { get; set; }
/// <summary>
/// Момент на ВСП, кН*м план
/// </summary>
[Range(0, 99999.9, ErrorMessage = "Момент на ВСП, кН*м должна быть в пределах от 0 до 99999.9")]
[Range(0, 99999.9, ErrorMessage = "Момент на ВСП, кН*м должна быть в пределах от 0 до 99999.9")]
public double TopDriveTorquePlan { get; set; }
/// <summary>
/// Момент на ВСП, кН*м ограничение
/// </summary>
[Range(0, 99999.9, ErrorMessage = "Момент на ВСП, кН*м должна быть в пределах от 0 до 99999.9")]
[Range(0, 99999.9, ErrorMessage = "Момент на ВСП, кН*м должна быть в пределах от 0 до 99999.9")]
public double TopDriveTorqueLimitMax { get; set; }
/// <summary>
/// Обороты на ВСП, об/мин план
/// </summary>
[Range(0, 99999.9, ErrorMessage = "Обороты на ВСП, об/мин должна быть в пределах от 0 до 99999.9")]
[Range(0, 99999.9, ErrorMessage = "Обороты на ВСП, об/мин должна быть в пределах от 0 до 99999.9")]
public double TopDriveSpeedPlan { get; set; }
/// <summary>
/// Обороты на ВСП, об/мин ограничение
/// </summary>
[Range(0, 99999.9, ErrorMessage = "Обороты на ВСП, об/мин должна быть в пределах от 0 до 99999.9")]
[Range(0, 99999.9, ErrorMessage = "Обороты на ВСП, об/мин должна быть в пределах от 0 до 99999.9")]
public double TopDriveSpeedLimitMax { get; set; }
/// <summary>
/// Расход, л/с план
/// </summary>
[Range(0, 99999.9, ErrorMessage = "Расход, л/с должна быть в пределах от 0 до 99999.9")]
[Range(0, 99999.9, ErrorMessage = "Расход, л/с должна быть в пределах от 0 до 99999.9")]
public double FlowPlan { get; set; }
/// <summary>

View File

@ -6,7 +6,7 @@ namespace AsbCloudApp.Data.ProcessMaps;
/// <summary>
/// РТК план проработка скважины
/// </summary>
public class ProcessMapPlanWellReamDto : ProcessMapPlanBaseDto, IValidatableObject
public class ProcessMapPlanReamDto : ProcessMapPlanBaseDto, IValidatableObject
{
/// <summary>
/// Количество повторений

View File

@ -1,67 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data.ProcessMaps;
/// <summary>
/// РТК план бурение скважины
/// </summary>
public class ProcessMapPlanWellDrillingDto : ProcessMapPlanBaseDto
{
/// <summary>
/// Id режима 0-ручной, 1-ротор, 2 - слайд
/// </summary>
[Required]
[Range(0, 2, ErrorMessage = "Id режима должен быть либо 0-ручной либо, 1-ротор либо 2-слайд")]
public int IdMode { get; set; }
/// <summary>
/// Нагрузка
/// </summary>
[Required]
public PlanLimitDto AxialLoad { get; set; } = null!;
/// <summary>
/// Перепад давления
/// </summary>
[Required]
public PlanLimitDto Pressure { get; set; } = null!;
/// <summary>
/// Момент на ВСП
/// </summary>
[Required]
public PlanLimitDto TopDriveTorque { get; set; } = null!;
/// <summary>
/// Обороты на ВСП
/// </summary>
[Required]
public PlanLimitDto TopDriveSpeed { get; set; } = null!;
/// <summary>
/// Расход
/// </summary>
[Required]
public PlanLimitDto Flow { get; set; } = null!;
/// <summary>
/// Плановая механическая скорость, м/ч
/// </summary>
[Required]
[Range(0, 99999.9, ErrorMessage = "Плановая механическая скорость должно быть в пределах от 0 до 99999.9")]
public double RopPlan { get; set; }
/// <summary>
/// Плановый процент использования АКБ
/// </summary>
[Required]
[Range(0, 100, ErrorMessage = "Процент использования АКБ должен быть в пределах от 0 до 100")]
public double UsageSaub { get; set; }
/// <summary>
/// Плановый процент использования spin master
/// </summary>
[Required]
[Range(0, 100, ErrorMessage = "Процент использования spin master должен быть в пределах от 0 до 100")]
public double UsageSpin { get; set; }
}

View File

@ -0,0 +1,93 @@
using System;
namespace AsbCloudApp.Data.ProcessMaps.Report;
/// <summary>
/// Модель РТК
/// </summary>
public class ProcessMapReportDataSaubStatDto
{
/// <summary>
/// Время, затраченное на бурение интервала, в часах
/// </summary>
public double DrilledTime { get; set; } = 0;
/// <summary>
/// Id секции скважины
/// </summary>
public int IdWellSectionType { get; set; }
/// <summary>
/// Название секции скважины
/// </summary>
public string WellSectionTypeName { get; set; } = null!;
/// <summary>
/// Глубина по стволу от, м
/// <para>
/// на начало интервала
/// </para>
/// </summary>
public double DepthStart { get; set; }
/// <summary>
/// Глубина по стволу до, м
/// <para>
/// на конец интервала
/// </para>
/// </summary>
public double DepthEnd { get; set; }
/// <summary>
/// Дата/ время
/// <para>
/// на начало интервала
/// </para>
/// </summary>
public DateTime DateStart { get; set; }
/// <summary>
/// Режим бурения (Ротор/слайд/ручной)
/// </summary>
public string DrillingMode { get; set; } = null!;
/// <summary>
/// Проходка, м
/// </summary>
public double? DeltaDepth { get; set; }
/// <summary>
/// Перепад давления, атм
/// </summary>
public ProcessMapReportDataSaubStatParamsDto PressureDiff { get; set; } = new();
/// <summary>
/// Нагрузка, т
/// </summary>
public ProcessMapReportDataSaubStatParamsDto AxialLoad { get; set; } = new();
/// <summary>
/// Момент на ВСП, кНхМ
/// </summary>
public ProcessMapReportDataSaubStatParamsDto TopDriveTorque { get; set; } = new();
/// <summary>
/// Ограничение скорости, м/ч
/// </summary>
public ProcessMapReportDataSaubStatParamsDto SpeedLimit { get; set; } = new();
/// <summary>
/// Обороты ВСП, об/мин
/// </summary>
public ProcessMapReportDataSaubStatParamsDto TopDriveSpeed { get; set; } = new();
/// <summary>
/// Расход, л/с
/// </summary>
public ProcessMapReportDataSaubStatParamsDto Flow { get; set; } = new();
/// <summary>
/// Механическая скорость, м/ч
/// </summary>
public PlanFactDto<double?> Rop { get; set; } = new();
}

View File

@ -0,0 +1,37 @@
namespace AsbCloudApp.Data.ProcessMaps.Report;
/// <summary>
/// Параметры РТК
/// </summary>
public class ProcessMapReportDataSaubStatParamsDto
{
/// <summary>
/// Уставка план
/// </summary>
public double? SetpointPlan { get; set; }
/// <summary>
/// Уставка факт
/// </summary>
public double? SetpointFact { get; set; }
/// <summary>
/// Факт (средневзвешенное)
/// </summary>
public double? FactWavg { get; set; }
/// <summary>
/// Факт (максимум)
/// </summary>
public double? FactMax { get; set; }
/// <summary>
/// Ограничение
/// </summary>
public double? Limit { get; set; }
/// <summary>
/// Процент бурения по уставке, %
/// </summary>
public double? SetpointUsage { get; set; }
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace AsbCloudApp.Data.SAUB
{
/// <summary>
/// DTO для получения записи drill_test из панели
/// </summary>
public class DrillTestBaseDto
{
/// <summary>
/// Идентификатор drill test
/// </summary>
[Required]
public int Id { get; set; }
/// <summary>
/// Время начала drill test
/// </summary>
[Required]
public DateTimeOffset TimeStampStart { get; set; }
/// <summary>
/// Глубина начала drill test
/// </summary>
[Required]
public float DepthStart { get; set; }
/// <summary>
/// Параметры теста
/// </summary>
[Required]
public IEnumerable<DrillTestParamsDto> Params { get; set; } = Enumerable.Empty<DrillTestParamsDto>();
}
}

View File

@ -1,42 +1,15 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data.SAUB
{
/// <summary>
/// DTO для описания записи drill_test
/// DTO для отображения записи drill_test
/// </summary>
public class DrillTestDto
public class DrillTestDto : DrillTestBaseDto
{
/// <summary>
/// Идентификатор drill test
/// </summary>
[Required]
public int Id { get; set; }
/// <summary>
/// Время начала drill test
/// </summary>
[Required]
public DateTimeOffset TimeStampStart { get; set; }
/// <summary>
/// Глубина начала drill test
/// </summary>
[Required]
public float DepthStart { get; set; }
/// <summary>
/// Связанная с drill_test телеметрия
/// </summary>
public TelemetryDto? Telemetry { get; set; }
/// <summary>
/// Параметры теста
/// </summary>
[Required]
public IEnumerable<DrillTestParamsDto> Params { get; set; } = Enumerable.Empty<DrillTestParamsDto>();
}
}

View File

@ -39,7 +39,8 @@ namespace AsbCloudApp.Data.SAUB
/// время в секундах актуальности этого запроса
/// </summary>
[Required]
public int ObsolescenceSec { get; set; }
[Range(10 * 60, 4 * 60 * 60)]
public int ObsolescenceSec { get; set; } = 10 * 60;
/// <summary>
/// набор уставок: {"название переменной панели"; "рекомендуемое значение"}

View File

@ -13,6 +13,11 @@ namespace AsbCloudApp.Data.SAUB
/// </summary>
[Required]
public DateTime DateTime { get; set; }
/// <summary>
/// Пользователь САУБ
/// </summary>
public int? IdUser { get; set; }
/// <summary>
/// Режим работы САУБ:

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data
@ -6,7 +7,7 @@ namespace AsbCloudApp.Data
/// <summary>
/// Описание данных графика работ
/// </summary>
public class ScheduleDto : IId, IWellRelated
public class ScheduleDto : IId, IWellRelated, IValidatableObject
{
/// <inheritdoc/>
[Required]
@ -50,5 +51,12 @@ namespace AsbCloudApp.Data
/// Бурильщик
/// </summary>
public DrillerDto? Driller { get; set; }
/// <inheritdoc/>
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(DrillStart >= DrillEnd)
yield return new ValidationResult($"DrillStart > DrillEnd");
}
}
}

View File

@ -1,25 +1,32 @@
using System;
namespace AsbCloudApp.Data
{
/// <summary>
/// временная зона
/// временная зона
/// </summary>
public class SimpleTimezoneDto
{
/// <summary>
/// смещение в часах относительно UTC
/// смещение в часах относительно UTC
/// </summary>
public double Hours { get; set; }
/// <summary>
/// идентификатор часовой зоны
/// идентификатор часовой зоны
/// </summary>
public string? TimezoneId { get; set; }
/// <summary>
/// запрет на переопределение
/// запрет на переопределение
/// </summary>
public bool IsOverride { get; set; }
/// <summary>
/// Смещение часового пояса
/// </summary>
public TimeSpan Offset => TimeSpan.FromHours(Hours);
/// <inheritdoc/>
public override bool Equals(object? obj)
{

View File

@ -86,6 +86,14 @@ namespace AsbCloudApp.Data
second = fullDate.Second;
}
/// <inheritdoc/>
public TimeDto(DateTimeOffset fullDate)
{
hour = fullDate.Hour;
minute = fullDate.Minute;
second = fullDate.Second;
}
/// <summary>
/// Makes System.TimeOnly
/// </summary>

View File

@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace AsbCloudApp.Data.Trajectory
{
/// <summary>
/// Базовая географическая траектория
/// </summary>
public abstract class TrajectoryGeoDto
public abstract class TrajectoryGeoDto : IId, IValidatableObject
{
/// <summary>
/// ИД строки с координатами
@ -49,5 +52,11 @@ namespace AsbCloudApp.Data.Trajectory
/// ИД пользователя
/// </summary>
public int IdUser { get; set; }
/// <inheritdoc />
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return Enumerable.Empty<ValidationResult>();
}
}
}

View File

@ -0,0 +1,39 @@
namespace AsbCloudApp.Data
{
/// Операция на скважине
public class WellOperationDataDto : IWellRelated
{
/// <inheritdoc/>
public int IdWell { get; set; }
/// <summary>
/// id секции скважины
/// </summary>
public int IdWellSectionType { get; set; }
/// <summary>
/// id категории операции
/// </summary>
public int IdCategory { get; set; }
/// <summary>
/// Глубина на начало операции, м
/// </summary>
public double DepthStart { get; set; }
/// <summary>
/// Продолжительность, часы
/// </summary>
public double DurationHours { get; set; }
/// <summary>
/// Наименование секции
/// </summary>
public string WellSectionTypeCaption { get; set; } = string.Empty;
/// <summary>
/// Наименование категории
/// </summary>
public string OperationCategoryName { get; set; } = string.Empty;
}
}

View File

@ -14,6 +14,7 @@ namespace AsbCloudApp.Exceptions
/// </summary>
public IDictionary<string, string[]> ErrorState { get; } = null!;
// TODO: swap arguments, inherit from ArgumentException
/// <summary>
/// конструктор
/// </summary>

View File

@ -0,0 +1,32 @@
using AsbCloudApp.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AsbCloudApp.Extensions
{
/// <summary>
/// Расширения для поиска в истории
/// </summary>
public static class ChangeLogExtensions
{
/// <summary>
/// Действительные на момент времени значения
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="items"></param>
/// <param name="moment"></param>
/// <returns></returns>
public static IEnumerable<T> WhereActualAtMoment<T>(this IEnumerable<T> items, DateTimeOffset moment)
where T : ChangeLogAbstract
{
var actualItems = items
.Where(item => item.Creation <= moment)
.Where(item => item.Obsolete is null || item.Obsolete >= moment);
return actualItems;
}
}
}

View File

@ -93,6 +93,4 @@ public interface IChangeLogRepository<TDto, TRequest>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<TDto>> Get(TRequest request, CancellationToken token);
}

View File

@ -0,0 +1,40 @@
using AsbCloudApp.Data;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Repositories
{
/// <summary>
/// Репозиторий работы с данными из таблицы t_data_daub_stat
/// </summary>
public interface IDataSaubStatRepository
{
/// <summary>
/// Получение записей по ключу телеметрии
/// </summary>
/// <param name="idTelemetry">ключ телеметрии</param>
/// <param name="geDate">начальная дата</param>
/// <param name="leDate">конечная дата</param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DataSaubStatDto>> GetAsync(int idTelemetry, DateTimeOffset geDate, DateTimeOffset leDate, CancellationToken token);
/// <summary>
/// Получение последних по дате окончания бурения записей в разрезе телеметрий
/// </summary>
/// <param name="idTelemetries">ключи телеметрий</param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DataSaubStatDto>> GetLastsAsync(int[] idTelemetries, CancellationToken token);
/// <summary>
/// Вставка записей статистики
/// </summary>
/// <param name="dataSaubStats"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> InsertRangeAsync(IEnumerable<DataSaubStatDto> dataSaubStats, CancellationToken token);
}
}

View File

@ -0,0 +1,75 @@
using System;
using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Requests;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
using AsbCloudApp.Services;
namespace AsbCloudApp.Repositories;
/// <summary>
/// Таблица автоматически определенных операций
/// </summary>
public interface IDetectedOperationRepository : ICrudRepository<DetectedOperationDto>
{
/// <summary>
/// Добавление записей
/// </summary>
/// <param name="idUser"></param>
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> Insert(int? idUser, IEnumerable<DetectedOperationDto> dtos, CancellationToken token);
/// <summary>
/// Получить автоматически определенные операции по телеметрии
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DetectedOperationDto>> Get(DetectedOperationByTelemetryRequest request, CancellationToken token);
/// <summary>
/// Редактирование записей
/// </summary>
/// <param name="idUser"></param>
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> Update(int idUser, IEnumerable<DetectedOperationDto> dtos, CancellationToken token);
/// <summary>
/// Добавляет Dto у которых id == 0, изменяет dto у которых id != 0
/// </summary>
/// <param name="idUser"></param>
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> UpdateOrInsert(int idUser, IEnumerable<DetectedOperationDto> dtos, CancellationToken token);
/// <summary>
/// Удалить операции
/// </summary>
/// <param name="idUser"></param>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> Delete(int idUser, DetectedOperationByTelemetryRequest request, CancellationToken token);
/// <summary>
/// Удаление записей
/// </summary>
/// <param name="idUser"></param>
/// <param name="ids"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> DeleteRange(int idUser, IEnumerable<int> ids, CancellationToken token);
/// <summary>
/// Получение дат последних определённых операций
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
Task<IDictionary<int, DateTimeOffset>> GetLastDetectedDatesAsync(CancellationToken token);
}

View File

@ -36,6 +36,6 @@ namespace AsbCloudApp.Repositories
/// <param name="dto">запись drill test</param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> SaveDataAsync(int idTelemetry, DrillTestDto dto, CancellationToken token);
Task<int> SaveDataAsync(int idTelemetry, DrillTestBaseDto dto, CancellationToken token);
}
}

View File

@ -1,32 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using System;
namespace AsbCloudApp.Repositories;
/// <summary>
/// РТК план
/// </summary>
[Obsolete]
public interface IProcessMapPlanRepository<TDto> : IRepositoryWellRelated<TDto>
where TDto : ProcessMapPlanBaseDto
{
/// <summary>
/// Получить РТК по коллекции параметров
/// </summary>
/// <param name="requests"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IEnumerable<TDto>> GetAsync(IEnumerable<ProcessMapPlanRequest> requests, CancellationToken cancellationToken);
/// <summary>
/// Удалить РТК по скважине
/// </summary>
/// <param name="idWell"></param>
/// <returns></returns>
Task<int> RemoveByWellAsync(int idWell);
}

View File

@ -72,5 +72,12 @@ namespace AsbCloudApp.Repositories
/// </summary>
/// <returns></returns>
IEnumerable<TelemetryDataStatDto> GetStat();
/// <summary>
/// Получить ключи телеметрии по параметрам запроса
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
IEnumerable<int> GetIds(TelemetryDataRequest request);
}
}

View File

@ -1,8 +1,8 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.ProcessMaps;
namespace AsbCloudApp.Repositories
{
@ -34,6 +34,6 @@ namespace AsbCloudApp.Repositories
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ProcessMapPlanWellDrillingDto>> GetCompositeProcessMap(int idWell, CancellationToken token);
Task<IEnumerable<ProcessMapPlanDrillingDto>> GetCompositeProcessMap(int idWell, CancellationToken token);
}
}

View File

@ -0,0 +1,17 @@
using AsbCloudApp.Data;
using System.Collections.Generic;
namespace AsbCloudApp.Repositories
{
/// <summary>
/// сервис операций по скважине
/// </summary>
public interface IWellOperationCategoryRepository
{
/// <summary>
/// список названий операций
/// </summary>
/// <returns></returns>
IEnumerable<WellOperationCategoryDto> Get(bool includeParents);
}
}

View File

@ -2,7 +2,6 @@
using AsbCloudApp.Requests;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading;
using System.Threading.Tasks;
@ -13,12 +12,6 @@ namespace AsbCloudApp.Repositories
/// </summary>
public interface IWellOperationRepository
{
/// <summary>
/// список названий операций
/// </summary>
/// <returns></returns>
IEnumerable<WellOperationCategoryDto> GetCategories(bool includeParents);
/// <summary>
/// Список секций
/// </summary>
@ -49,6 +42,14 @@ namespace AsbCloudApp.Repositories
/// <returns></returns>
Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token);
/// <summary>
/// Получить список операций по запросу
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<WellOperationDataDto>> GetAsync(WellsOperationRequest request, CancellationToken token);
/// <summary>
/// Получить страницу списка операций
/// </summary>
@ -117,18 +118,21 @@ namespace AsbCloudApp.Repositories
Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken);
/// <summary>
/// Валидация данных
/// Удаление полных дубликатов операций по всем скважинам
/// </summary>
/// <param name="wellOperations"></param>
/// <param name="onProgressCallback"></param>
/// <param name="token"></param>
/// <returns></returns>
IEnumerable<ValidationResult> Validate(IEnumerable<WellOperationDto> wellOperations);
Task<int> RemoveDuplicates(Action<string, double?> onProgressCallback, CancellationToken token);
/// <summary>
/// Валидация данных (проверка с базой)
/// Усечение пересекающейся последующей операции по дате и глубине забоя
/// </summary>
/// <param name="wellOperations"></param>
/// <param name="cancellationToken"></param>
/// <param name="geDate">Фильтр по дате. Если хоть одна операция попадет в в фильтр, то будет обработана вся скважина, а не только эта операция</param>
/// <param name="leDate">Фильтр по дате. Если хоть одна операция попадет в в фильтр, то будет обработана вся скважина, а не только эта операция</param>
/// <param name="onProgressCallback"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ValidationResult>> ValidateWithDbAsync(IEnumerable<WellOperationDto> wellOperations, CancellationToken cancellationToken);
Task<int> TrimOverlapping(DateTimeOffset? geDate, DateTimeOffset leDate, Action<string, double?> onProgressCallback, CancellationToken token);
}
}

View File

@ -8,7 +8,7 @@ namespace AsbCloudApp.Requests;
public class ChangeLogBaseRequest
{
/// <summary>
/// Дата/время на которую записи были актуальны. Если не задано, то не фильтруется
/// Дата/время на которую записи были актуальны. Если не задано, то возвращаются все данные без учета их актуальности
/// </summary>
public DateTimeOffset? Moment { get; set; }
}

View File

@ -0,0 +1,41 @@
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Requests
{
/// <summary>
/// Параметры запроса для построения отчёта
/// </summary>
public class DataSaubStatRequest
{
/// <summary>
/// Изменение уставки факт перепада давления от первого значения в начале интервала
/// Не менее 5 атм и не более 15(50) атм;
/// </summary>
[Range(5, 15, ErrorMessage = "Изменение уставки факт перепада давления не может быть меньше 5 и больше 15 атм")]
public double DeltaPressure { get; set; } = 5d;
/// <summary>
/// Изменение уставки факт осевой нагрузки от первого значения в начале интервала
/// Не менее 1 т и не более 5(20) т;
/// </summary>
[Range(1, 5, ErrorMessage = "Изменение уставки факт осевой нагрузки не может быть меньше 1 и больше 5 т")]
public double DeltaAxialLoad { get; set; } = 1d;
/// <summary>
/// Изменение уставки момента от первого значения в начале интервала
/// Не менее 5 кН*м и не более 10(20) кН*м.
/// </summary>
[Range(5, 10, ErrorMessage = "Изменение уставки момента не может быть меньше 5 и больше 10 кН*м")]
public double DeltaRotorTorque { get; set; } = 5d;
/// <summary>
/// Изменение ограничения нагрузки от первого значения в начале интервала
/// </summary>
public double DeltaAxialLoadSp => 1.0;
/// <summary>
/// Изменение ограничения момента от первого значения в начале интервала
/// </summary>
public double DeltaRotorTorqueSp => 5.0;
}
}

View File

@ -1,56 +1,114 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace AsbCloudApp.Requests
namespace AsbCloudApp.Requests;
/// <summary>
/// Запрос на получение операций определенных по телеметрии
/// </summary>
public class DetectedOperationByTelemetryRequest : DetectedOperationRequest
{
/// <summary>
/// Параметры запроса на получение операций определенных по телеметрии
/// id телеметрии
/// </summary>
public class DetectedOperationRequest : RequestBase
[Required]
public int IdTelemetry { get; set; }
/// <summary>
/// Запрос на получение операций определенных по id телеметрии
/// </summary>
public DetectedOperationByTelemetryRequest()
{}
/// <summary>
/// Запрос на получение операций определенных по id телеметрии. Copy
/// </summary>
/// <param name="idTelemetry"></param>
/// <param name="request"></param>
public DetectedOperationByTelemetryRequest(int idTelemetry, DetectedOperationRequest request)
:base(request)
{
/// <summary>
/// категория операций
/// </summary>
[Required]
public int IdWell { get; set; }
/// <summary>
/// Список id телеметрий
/// пустой список - нет фильтрации
/// </summary>
public IEnumerable<int> IdsTelemetries { get; set; } = Array.Empty<int>();
/// <summary>
/// категории операций
/// </summary>
public IEnumerable<int> IdsCategories { get; set; } = Array.Empty<int>();
/// <summary>
/// Больше или равно дате
/// </summary>
public DateTimeOffset? GeDateStart { get; set; }
/// <summary>
/// Меньше или равно дате
/// </summary>
public DateTimeOffset? LeDateEnd { get; set; }
/// <summary>
/// Больше или равно глубины забоя
/// </summary>
public double? GeDepth { get; set; }
/// <summary>
/// Меньше или равно глубины забоя
/// </summary>
public double? LeDepth { get; set; }
/// <summary>
/// Фильтр по пользователю панели
/// </summary>
public int? IdTelemetryUser { get; set; }
IdTelemetry = idTelemetry;
}
}
/// <summary>
/// Запрос на получение операций определенных по id скважины
/// </summary>
public class DetectedOperationByWellRequest : DetectedOperationRequest
{
/// <summary>
/// id скважины
/// </summary>
[Required]
public int IdWell { get; set; }
/// <summary>
/// Запрос на получение операций определенных по id скважины
/// </summary>
public DetectedOperationByWellRequest()
{}
/// <summary>
/// Запрос на получение операций определенных по id скважины. Copy
/// </summary>
public DetectedOperationByWellRequest(int idWell, DetectedOperationRequest request)
: base(request)
{
IdWell = idWell;
}
}
/// <summary>
/// Запрос на получение операций определенных по телеметрии
/// </summary>
public class DetectedOperationRequest : RequestBase
{
/// <summary>
/// категории операций
/// </summary>
public IEnumerable<int> IdsCategories { get; set; }
/// <summary>
/// Больше или равно дате
/// </summary>
public DateTimeOffset? GeDateStart { get; set; }
/// <summary>
/// Меньше или равно дате
/// </summary>
public DateTimeOffset? LeDateEnd { get; set; }
/// <summary>
/// Больше или равно глубины забоя
/// </summary>
public double? GeDepthStart { get; set; }
/// <summary>
/// Меньше или равно глубины забоя
/// </summary>
public double? LeDepthEnd { get; set; }
/// <summary>
/// Запрос на получение операций определенных по телеметрии
/// </summary>
public DetectedOperationRequest()
{
IdsCategories = new List<int>();
}
/// <summary>
/// Запрос на получение операций определенных по телеметрии. Copy
/// </summary>
/// <param name="request"></param>
public DetectedOperationRequest(DetectedOperationRequest request)
: base(request)
{
IdsCategories = request.IdsCategories;
GeDateStart = request.GeDateStart;
LeDateEnd = request.LeDateEnd;
GeDepthStart = request.GeDepthStart;
LeDepthEnd = request.LeDepthEnd;
}
}

View File

@ -0,0 +1,8 @@
namespace AsbCloudApp.Requests.ExportOptions;
/// <summary>
/// Параметры экспорта
/// </summary>
public interface IExportOptionsRequest
{
}

View File

@ -0,0 +1,21 @@
namespace AsbCloudApp.Requests.ExportOptions;
/// <summary>
/// Параметры экспорта
/// </summary>
public class WellRelatedExportRequest : IExportOptionsRequest
{
/// <summary>
/// Конструктор
/// </summary>
/// <param name="idWell">Id скважины</param>
public WellRelatedExportRequest(int idWell)
{
IdWell = idWell;
}
/// <summary>
/// Id скважины
/// </summary>
public int IdWell { get; }
}

View File

@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudApp.Requests;
/// <summary>
/// Çàïðîñ íà ïîëó÷åíèå ñòàòèñòèêè èñïîëüçîâàíèÿ ïîäñèñòåì áóðèëüùèêîì
/// </summary>
public class GetStatRequest: RequestBase
{
/// <summary>
/// id ñêâàæèí
/// </summary>
public IEnumerable<int> IdsWells { get; set; } = new List<int>();
/// <summary>
/// id Áóðèëüùèêà
/// </summary>
public int? IdDriller { get; set; }
}

View File

@ -0,0 +1,19 @@
namespace AsbCloudApp.Requests.ParserOptions;
/// <summary>
/// Параметры парсинга
/// </summary>
public interface IParserOptionsRequest
{
private static DummyOptions empty => new();
private class DummyOptions : IParserOptionsRequest
{
}
/// <summary>
/// Получение пустого объекта опций
/// </summary>
/// <returns></returns>
public static IParserOptionsRequest Empty() => empty;
}

View File

@ -0,0 +1,21 @@
namespace AsbCloudApp.Requests.ParserOptions;
/// <summary>
/// Параметры парсинга
/// </summary>
public class WellRelatedParserRequest : IParserOptionsRequest
{
/// <summary>
/// Конструктор
/// </summary>
/// <param name="idWell">Id скважины</param>
public WellRelatedParserRequest(int idWell)
{
IdWell = idWell;
}
/// <summary>
/// Id скважины
/// </summary>
public int IdWell { get; }
}

View File

@ -23,5 +23,23 @@ namespace AsbCloudApp.Requests
/// Указать направление сортировки можно через пробел "asc" или "desc"
/// </summary>
public IEnumerable<string>? SortFields { get; set; }
/// <summary>
/// Базовые параметры запроса
/// </summary>
public RequestBase()
{
}
/// <summary>
/// Базовые параметры запроса. Копирующий конструктор
/// </summary>
/// <param name="request"></param>
public RequestBase(RequestBase request)
{
Skip = request.Skip;
Take = request.Take;
SortFields = request.SortFields;
}
}
}

View File

@ -6,7 +6,7 @@ namespace AsbCloudApp.Requests
/// <summary>
/// параметры для запроса списка операций
/// </summary>
public class WellOperationRequestBase: RequestBase
public class WellOperationRequestBase : RequestBase
{
/// <summary>
/// фильтр по дате начала операции
@ -42,12 +42,40 @@ namespace AsbCloudApp.Requests
/// фильтр по списку id конструкций секции
/// </summary>
public IEnumerable<int>? SectionTypeIds { get; set; }
/// <summary>
/// Параметры для запроса списка операций.
/// Базовый конструктор
/// </summary>
public WellOperationRequestBase()
{ }
/// <summary>
/// Параметры для запроса списка операций.
/// Копирующий конструктор
/// </summary>
/// <param name="request"></param>
public WellOperationRequestBase(WellOperationRequestBase request)
{
GeDepth = request.GeDepth;
LeDepth = request.LeDepth;
GeDate = request.GeDate;
LtDate = request.LtDate;
OperationCategoryIds = request.OperationCategoryIds;
OperationType = request.OperationType;
SectionTypeIds = request.SectionTypeIds;
Skip = request.Skip;
Take = request.Take;
SortFields = request.SortFields;
}
}
/// <summary>
/// Параметры для запроса списка операций (с id скважины)
/// </summary>
public class WellOperationRequest: WellOperationRequestBase
public class WellOperationRequest : WellOperationRequestBase
{
/// <summary>
/// id скважины
@ -57,7 +85,7 @@ namespace AsbCloudApp.Requests
/// <summary>
/// ctor
/// </summary>
public WellOperationRequest(){}
public WellOperationRequest() { }
/// <summary>
/// копирующий конструктор
@ -65,21 +93,20 @@ namespace AsbCloudApp.Requests
/// <param name="request"></param>
/// <param name="idWell"></param>
public WellOperationRequest(WellOperationRequestBase request, int idWell)
:base(request)
{
this.IdWell = idWell;
this.GeDepth = request.GeDepth;
this.LeDepth = request.LeDepth;
this.GeDate = request.GeDate;
this.LtDate = request.LtDate;
this.OperationCategoryIds = request.OperationCategoryIds;
this.OperationType = request.OperationType;
this.SectionTypeIds = request.SectionTypeIds;
this.Skip= request.Skip;
this.Take= request.Take;
this.SortFields = request.SortFields;
IdWell = idWell;
}
}
/// <summary>
/// Параметры для запроса списка операций (с массивом id скважин)
/// </summary>
public class WellsOperationRequest : WellOperationRequestBase
{
/// <summary>
/// ids скважин
/// </summary>
public IEnumerable<int> IdsWell { get; set; } = null!;
}
}

View File

@ -1,4 +1,5 @@
using AsbCloudApp.Data;
using System;
using AsbCloudApp.Data;
using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Requests;
using System.Collections.Generic;
@ -19,7 +20,7 @@ namespace AsbCloudApp.Services
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<WellOperationCategoryDto>?> GetCategoriesAsync(int? idWell, CancellationToken token);
Task<IEnumerable<WellOperationCategoryDto>> GetCategoriesAsync(int? idWell, CancellationToken token);
/// <summary>
/// Получить автоматически определенные по телеметрии операции с анализом по бурильщикам
@ -27,7 +28,7 @@ namespace AsbCloudApp.Services
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<DetectedOperationListDto?> GetAsync(DetectedOperationRequest request, CancellationToken token);
Task<DetectedOperationListDto> GetAsync(DetectedOperationByWellRequest request, CancellationToken token);
/// <summary>
/// Получить автоматически определенные по телеметрии операции
@ -35,7 +36,7 @@ namespace AsbCloudApp.Services
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DetectedOperationDto>> GetOperationsAsync(DetectedOperationRequest request, CancellationToken token);
Task<IEnumerable<DetectedOperationWithDrillerDto>> GetOperationsAsync(DetectedOperationByWellRequest request, CancellationToken token);
/// <summary>
/// Удалить операции
@ -43,7 +44,7 @@ namespace AsbCloudApp.Services
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> DeleteAsync(DetectedOperationRequest request, CancellationToken token);
Task<int> DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token);
/// <summary>
/// Статистика по операциям
@ -51,6 +52,15 @@ namespace AsbCloudApp.Services
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DetectedOperationStatDto>?> GetOperationsStatAsync(DetectedOperationRequest request, CancellationToken token);
Task<IEnumerable<DetectedOperationStatDto>> GetOperationsStatAsync(DetectedOperationByWellRequest request, CancellationToken token);
/// <summary>
/// Определение операций
/// </summary>
/// <param name="idTelemetry"></param>
/// <param name="beginDate"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DetectedOperationDto>> DetectOperationsAsync(int idTelemetry, DateTimeOffset? beginDate, CancellationToken token);
}
}

View File

@ -0,0 +1,21 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Requests.ExportOptions;
namespace AsbCloudApp.Services;
/// <summary>
/// Экспорт данных
/// </summary>
public interface IExportService<in TOptions>
where TOptions : IExportOptionsRequest
{
/// <summary>
/// Экспортировать данные
/// </summary>
/// <param name="options"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<(string FileName, Stream File)> ExportAsync(TOptions options, CancellationToken token);
}

View File

@ -0,0 +1,29 @@
using System.IO;
using AsbCloudApp.Data;
using AsbCloudApp.Requests.ParserOptions;
namespace AsbCloudApp.Services;
/// <summary>
/// Сервис парсинга
/// </summary>
/// <typeparam name="TDto"></typeparam>
/// <typeparam name="TOptions"></typeparam>
public interface IParserService<TDto, in TOptions>
where TDto : class, IId
where TOptions : IParserOptionsRequest
{
/// <summary>
/// Распарсить файл
/// </summary>
/// <param name="file"></param>
/// <param name="options"></param>
/// <returns></returns>
ParserResultDto<TDto> Parse(Stream file, TOptions options);
/// <summary>
/// Получение шаблона для заполнения
/// </summary>
/// <returns></returns>
Stream GetTemplateFile();
}

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Requests;
namespace AsbCloudApp.Services
{
@ -28,5 +29,13 @@ namespace AsbCloudApp.Services
/// <param name="token"></param>
/// <returns></returns>
Task<DrillerDto?> GetOrDefaultDrillerAsync(int idWell, DateTime workTime, CancellationToken token);
/// <summary>
/// Получить расписание смен
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ScheduleDto>> GetPageAsync(GetStatRequest request, CancellationToken token);
}
}

View File

@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
namespace AsbCloudApp.Services;
@ -26,5 +27,14 @@ public interface ISubsystemService
/// <param name="wellIds"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token);
Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token);
/// <summary>
/// Получение статистики по бурильщику
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DrillerDetectedOperationStatDto>> GetByWellsAsync(GetStatRequest request,
CancellationToken token);
}

View File

@ -12,6 +12,18 @@ namespace AsbCloudApp.Services
/// </summary>
public interface ITelemetryDataSaubService : ITelemetryDataService<TelemetryDataSaubDto>
{
/// <summary>
/// Получение телеметрии для РТК статистики
/// </summary>
/// <param name="idTelemetry"></param>
/// <param name="isBitOnBottom"></param>
/// <param name="geDate"></param>
/// <param name="leDate"></param>
/// <param name="take"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<TelemetryDataSaubDto>> Get(int idTelemetry, bool isBitOnBottom, DateTimeOffset geDate, DateTimeOffset leDate, int take, CancellationToken token);
/// <summary>
/// усредненная статистика по 1м за весь период
/// <para>

View File

@ -23,18 +23,27 @@ namespace AsbCloudApp.Services
/// <param name="approxPointsCount">кол-во элементов до которых эти данные прореживаются</param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<TDto>> GetAsync(int idWell,
Task<IEnumerable<TDto>> GetByWellAsync(int idWell,
DateTime dateBegin = default, double intervalSec = 600d,
int approxPointsCount = 1024, CancellationToken token = default);
/// <summary>
/// Получить данные тех. процесса
/// Получить данные тех. процесса по скважине
/// </summary>
/// <param name="idWell"></param>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<TDto>> GetAsync(int idWell, TelemetryDataRequest request, CancellationToken token);
Task<IEnumerable<TDto>> GetByWellAsync(int idWell, TelemetryDataRequest request, CancellationToken token);
/// <summary>
/// Получение данных тех. процесса по телеметрии
/// </summary>
/// <param name="idTelemetry"></param>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<TDto>> GetByTelemetryAsync(int idTelemetry, TelemetryDataRequest request, CancellationToken token);
/// <summary>
/// Период за который есть данные по скважине в рамках временного интервала

View File

@ -0,0 +1,21 @@
using AsbCloudApp.Data;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services
{
/// <summary>
/// Интерфейс для вычисления композитной скважины
/// </summary>
public interface IWellCompositeOperationService
{
/// <summary>
/// Получение данных для построения композитной скважины
/// </summary>
/// <param name="idsWells"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<List<Dictionary<int, WellOperationDataDto>>> GetAsync(IEnumerable<int> idsWells, CancellationToken token);
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
@ -60,7 +61,15 @@ public class NotificationService
var notificationTransportService = GetTransportService(request.IdTransportType);
await notificationTransportService.SendAsync(notification, cancellationToken);
//todo Добавить задачу в WorkToSendEmail
try
{
await notificationTransportService.SendAsync(notification, cancellationToken);
}
catch (SmtpException ex)
{
Console.WriteLine(ex.Message);
}
notification.SentDate = DateTime.UtcNow;
await notificationRepository.UpdateAsync(notification, cancellationToken);

View File

@ -1,37 +0,0 @@
using System.IO;
using System.Threading.Tasks;
using System.Threading;
namespace AsbCloudApp.Services.ProcessMaps;
/// <summary>
/// Сервис импорта РТК
/// </summary>
public interface IProcessMapPlanImportService
{
/// <summary>
/// Загрузить данные из файла
/// </summary>
/// <param name="idWell"></param>
/// <param name="idUser"></param>
/// <param name="deleteBeforeImport"></param>
/// <param name="stream"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task ImportAsync(int idWell, int idUser, bool deleteBeforeImport, Stream stream,
CancellationToken cancellationToken);
/// <summary>
/// Сформировать файл с данными
/// </summary>
/// <param name="idWell"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<(string Name, Stream File)> ExportAsync(int idWell, CancellationToken cancellationToken);
/// <summary>
/// Получение шаблона для заполнения
/// </summary>
/// <returns></returns>
Task<(string Name, Stream File)> GetExcelTemplateStreamAsync(CancellationToken cancellationToken);
}

View File

@ -1,22 +0,0 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
namespace AsbCloudApp.Services.ProcessMaps;
/// <summary>
/// РТК
/// </summary>
public interface IProcessMapPlanService<T>
where T : ProcessMapPlanBaseDto
{
/// <summary>
/// Получение РТК план по скважине
/// </summary>
/// <param name="idWell"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IEnumerable<ValidationResultDto<T>>> GetAsync(int idWell, CancellationToken cancellationToken);
}

View File

@ -0,0 +1,26 @@
using AsbCloudApp.Requests;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services.ProcessMaps.WellDrilling
{
/// <summary>
/// Сервис экспорт РТК
/// </summary>
public interface IProcessMapReportDrillingExportService
{
/// <summary>
/// Сформировать файл с данными
/// </summary>
/// <param name="idWell"></param>
/// <param name="request">параметры запроса</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<(string Name, Stream File)?> ExportAsync(int idWell, DataSaubStatRequest request, CancellationToken cancellationToken);
}
}

View File

@ -0,0 +1,22 @@
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Requests;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services.ProcessMaps.WellDrilling;
/// <summary>
/// РТК-отчет по бурению
/// </summary>
public interface IProcessMapReportDrillingService
{
/// <summary>
/// Получения строк РТК-отчёта
/// </summary>
/// <param name="idWell">ключ скважины</param>
/// <param name="request">параметры запроса</param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ProcessMapReportDataSaubStatDto>> GetAsync(int idWell, DataSaubStatRequest request, CancellationToken token);
}

View File

@ -1,19 +0,0 @@
using System.IO;
using System.Threading.Tasks;
using System.Threading;
namespace AsbCloudApp.Services.ProcessMaps.WellDrilling;
/// <summary>
/// Сервис экспорт РТК
/// </summary>
public interface IProcessMapReportWellDrillingExportService
{
/// <summary>
/// Сформировать файл с данными
/// </summary>
/// <param name="idWell"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<(string Name, Stream File)?> ExportAsync(int idWell, CancellationToken cancellationToken);
}

View File

@ -1,20 +0,0 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.ProcessMaps.Report;
namespace AsbCloudApp.Services.ProcessMaps.WellDrilling;
/// <summary>
/// Сервис формирования отчёта РТК бурение
/// </summary>
public interface IProcessMapReportWellDrillingService
{
/// <summary>
/// Получить отчёт РТК по бурению
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ProcessMapReportWellDrillingDto>> GetAsync(int idWell, CancellationToken token);
}

View File

@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.22">
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.22" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,34 @@
using AsbCloudDb.Model;
using Microsoft.EntityFrameworkCore;
using Npgsql;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudDb
{
public static class EFExtensionsExceptionHandling
{
public static async Task<int> SaveChangesWithExceptionHandling(this IAsbCloudDbContext db, CancellationToken token)
{
try
{
var result = await db.SaveChangesAsync(token);
return result;
}
catch (DbUpdateException ex)
{
if (ex.InnerException is PostgresException pgException)
TryConvertPostgresExceptionToValidateException(pgException);
throw;
}
}
private static void TryConvertPostgresExceptionToValidateException(PostgresException pgException)
{
if (pgException.SqlState == PostgresErrorCodes.ForeignKeyViolation)
// TODO: replace ArgumentException by new Exception
throw new ArgumentException(pgException.Message + "\r\n" + pgException.Detail, "dtos");
}
}
}

View File

@ -7,7 +7,7 @@ using System.Reflection;
namespace AsbCloudDb
{
public static class EFExtentionsSortBy
public static class EFExtensionsSortBy
{
struct TypeAcessor
{

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,77 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Add_Table_DataSaubStat : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "t_data_saub_stat",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
date_start = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата и время начала"),
date_end = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата и время окончания"),
depth_start = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина забоя по стволу начальная"),
depth_end = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина забоя по стволу конечная"),
speed = table.Column<double>(type: "double precision", nullable: false, comment: "Скорость бурения"),
block_speed_sp = table.Column<double>(type: "double precision", nullable: true, comment: "Ограничение скорости блока"),
pressure = table.Column<double>(type: "double precision", nullable: false, comment: "Давление"),
pressure_idle = table.Column<double>(type: "double precision", nullable: true, comment: "Давление холостого хода"),
pressure_sp = table.Column<double>(type: "double precision", nullable: true, comment: "Ограничение фактического давления"),
axial_load = table.Column<double>(type: "double precision", nullable: false, comment: "Фактическая нагрузка"),
axial_load_sp = table.Column<double>(type: "double precision", nullable: true, comment: "Ограничение факт. нагрузки"),
axial_load_limit_max = table.Column<double>(type: "double precision", nullable: true, comment: "Максимально допустимая нагрузка"),
rotor_torque = table.Column<double>(type: "double precision", nullable: false, comment: "Фактический момент"),
rotor_torque_sp = table.Column<double>(type: "double precision", nullable: true, comment: "Ограничение факт. момента"),
rotor_torque_limit_max = table.Column<double>(type: "double precision", nullable: true, comment: "Максимально допустимый момент"),
id_feed_regulator = table.Column<short>(type: "smallint", nullable: true, comment: "Работа при достижении ограничения"),
rotor_speed = table.Column<double>(type: "double precision", nullable: false, comment: "Фактическая скорость оборотов ВСП"),
id_category = table.Column<int>(type: "integer", nullable: false, comment: "Название автоопределённой операции"),
enabled_subsystems = table.Column<int>(type: "integer", nullable: false, comment: "Флаги подсистем"),
has_oscillation = table.Column<bool>(type: "boolean", nullable: false, comment: "Наличие или отсутствие осцилляции"),
flow = table.Column<double>(type: "double precision", nullable: false, comment: "Фактический расход"),
id_telemetry = table.Column<int>(type: "integer", nullable: false, comment: "Ключ телеметрии")
},
constraints: table =>
{
table.PrimaryKey("PK_t_data_saub_stat", x => x.id);
table.ForeignKey(
name: "FK_t_data_saub_stat_t_telemetry_id_telemetry",
column: x => x.id_telemetry,
principalTable: "t_telemetry",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_data_saub_stat_t_well_operation_category_id_category",
column: x => x.id_category,
principalTable: "t_well_operation_category",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
},
comment: "Кеш-таблица для хранения данных для РТК-отчета");
migrationBuilder.CreateIndex(
name: "IX_t_data_saub_stat_id_category",
table: "t_data_saub_stat",
column: "id_category");
migrationBuilder.CreateIndex(
name: "IX_t_data_saub_stat_id_telemetry",
table: "t_data_saub_stat",
column: "id_telemetry");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "t_data_saub_stat");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Migrate_ProcessMapPlanDrilling : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql
(@"insert " +
@"into " +
@"public.t_process_map_plan_drilling " +
@"(id, " +
@"id_mode, " +
@"axial_load_plan, " +
@"axial_load_limit_max, " +
@"delta_pressure_plan, " +
@"delta_pressure_limit_max, " +
@"top_drive_torque_plan, " +
@"top_drive_torque_limit_max, " +
@"top_drive_speed_plan, " +
@"top_drive_speed_limit_max, " +
@"flow_plan, " +
@"flow_limit_max, " +
@"rop_plan, " +
@"usage_saub, " +
@"usage_spin, " +
@"""comment"", " +
@"id_author, " +
@"id_editor, " +
@"creation, " +
@"obsolete, " +
@"id_state, " +
@"id_previous, " +
@"id_well, " +
@"id_wellsection_type, " +
@"depth_start, " +
@"depth_end) " +
@"select " +
@"tpmwd.id, " +
@"tpmwd.id_mode, " +
@"tpmwd.axial_load_plan, " +
@"tpmwd.axial_load_limit_max, " +
@"tpmwd.pressure_plan, " +
@"tpmwd.pressure_limit_max, " +
@"tpmwd.top_drive_torque_plan, " +
@"tpmwd.top_drive_torque_limit_max, " +
@"tpmwd.top_drive_speed_plan, " +
@"tpmwd.top_drive_speed_limit_max, " +
@"tpmwd.flow_plan, " +
@"tpmwd.flow_limit_max, " +
@"tpmwd.rop_plan, " +
@"tpmwd.usage_saub, " +
@"tpmwd.usage_spin, " +
@"format('%s', tpmwd.""comment""), " +
@"tpmwd.id_user, " +
@"null, " +
@"tpmwd.last_update - interval '1 year', " +
@"null, " +
@"0, " +
@"null, " +
@"tpmwd.id_well, " +
@"tpmwd.id_wellsection_type, " +
@"tpmwd.depth_start, " +
@"tpmwd.depth_end " +
@"from t_process_map_well_drilling tpmwd;");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Add_ProcessMapPlanReams : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "t_process_map_plan_ream",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false, comment: "Идентификатор")
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
repeats = table.Column<double>(type: "double precision", nullable: false, comment: "Количество повторений"),
spin_upward = table.Column<double>(type: "double precision", nullable: false, comment: "Вращение при движении вверх, об/мин"),
spin_downward = table.Column<double>(type: "double precision", nullable: false, comment: "Вращение при движении вниз, об/мин"),
speed_upward = table.Column<double>(type: "double precision", nullable: false, comment: "Скорость подъёма, м/ч"),
speed_downward = table.Column<double>(type: "double precision", nullable: false, comment: "Скорость спуска, м/ч"),
setpoint_drag = table.Column<double>(type: "double precision", nullable: false, comment: "Уставка зятяжки, т"),
setpoint_tight = table.Column<double>(type: "double precision", nullable: false, comment: "Уставка посадки, т"),
pressure = table.Column<double>(type: "double precision", nullable: false, comment: "Давление, атм"),
torque = table.Column<double>(type: "double precision", nullable: false, comment: "Момент, кН*м"),
id_author = table.Column<int>(type: "integer", nullable: false, comment: "Автор"),
id_editor = table.Column<int>(type: "integer", nullable: true, comment: "Редактор"),
creation = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "дата создания"),
obsolete = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true, comment: "дата устаревания"),
id_state = table.Column<int>(type: "integer", nullable: false, comment: "ИД состояния записи: \n0 - актуальная\n1 - замененная\n2 - удаленная"),
id_previous = table.Column<int>(type: "integer", nullable: true, comment: "ИД состояния записи: \n0 - актуальная\n1 - замененная\n2 - удаленная"),
id_well = table.Column<int>(type: "integer", nullable: false, comment: "Id скважины"),
id_wellsection_type = table.Column<int>(type: "integer", nullable: false, comment: "Тип секции"),
depth_start = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу от, м"),
depth_end = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу до, м")
},
constraints: table =>
{
table.PrimaryKey("PK_t_process_map_plan_ream", x => x.id);
table.ForeignKey(
name: "FK_t_process_map_plan_ream_t_user_id_author",
column: x => x.id_author,
principalTable: "t_user",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_process_map_plan_ream_t_user_id_editor",
column: x => x.id_editor,
principalTable: "t_user",
principalColumn: "id");
table.ForeignKey(
name: "FK_t_process_map_plan_ream_t_well_id_well",
column: x => x.id_well,
principalTable: "t_well",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_process_map_plan_ream_t_well_section_type_id_wellsection_~",
column: x => x.id_wellsection_type,
principalTable: "t_well_section_type",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
},
comment: "РТК проработка скважины");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_plan_ream_id_author",
table: "t_process_map_plan_ream",
column: "id_author");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_plan_ream_id_editor",
table: "t_process_map_plan_ream",
column: "id_editor");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_plan_ream_id_well",
table: "t_process_map_plan_ream",
column: "id_well");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_plan_ream_id_wellsection_type",
table: "t_process_map_plan_ream",
column: "id_wellsection_type");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "t_process_map_plan_ream");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,152 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Remove_old_ProcessMapPlans : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "t_process_map_well_drilling");
migrationBuilder.DropTable(
name: "t_process_map_well_ream");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "t_process_map_well_drilling",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
id_user = table.Column<int>(type: "integer", nullable: false, comment: "Id пользователя"),
id_well = table.Column<int>(type: "integer", nullable: false, comment: "Id скважины"),
id_wellsection_type = table.Column<int>(type: "integer", nullable: false, comment: "Тип секции"),
axial_load_limit_max = table.Column<double>(type: "double precision", nullable: false, comment: "Нагрузка, допустимый максимум"),
axial_load_plan = table.Column<double>(type: "double precision", nullable: false, comment: "Нагрузка, план"),
comment = table.Column<string>(type: "text", nullable: true, comment: "Комментарий"),
depth_end = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу до, м"),
depth_start = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу от, м"),
flow_limit_max = table.Column<double>(type: "double precision", nullable: false, comment: "Расход, допустимый максимум"),
flow_plan = table.Column<double>(type: "double precision", nullable: false, comment: "Расход, план"),
id_mode = table.Column<int>(type: "integer", nullable: false, comment: "Id режима (1- ротор, 2 слайд)"),
last_update = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата последнего изменения"),
pressure_limit_max = table.Column<double>(type: "double precision", nullable: false, comment: "Перепад давления, допустимый максимум"),
pressure_plan = table.Column<double>(type: "double precision", nullable: false, comment: "Перепад давления, план"),
rop_plan = table.Column<double>(type: "double precision", nullable: false, comment: "Плановая механическая скорость, м/ч"),
top_drive_speed_limit_max = table.Column<double>(type: "double precision", nullable: false, comment: "Обороты на ВСП, допустимый максимум"),
top_drive_speed_plan = table.Column<double>(type: "double precision", nullable: false, comment: "Обороты на ВСП, план"),
top_drive_torque_limit_max = table.Column<double>(type: "double precision", nullable: false, comment: "Момент на ВСП, допустимый максимум"),
top_drive_torque_plan = table.Column<double>(type: "double precision", nullable: false, comment: "Момент на ВСП, план"),
usage_saub = table.Column<double>(type: "double precision", nullable: false, comment: "Плановый процент использования АКБ"),
usage_spin = table.Column<double>(type: "double precision", nullable: false, comment: "Плановый процент использования spin master")
},
constraints: table =>
{
table.PrimaryKey("PK_t_process_map_well_drilling", x => x.id);
table.ForeignKey(
name: "FK_t_process_map_well_drilling_t_user_id_user",
column: x => x.id_user,
principalTable: "t_user",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_process_map_well_drilling_t_well_id_well",
column: x => x.id_well,
principalTable: "t_well",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_process_map_well_drilling_t_well_section_type_id_wellsect~",
column: x => x.id_wellsection_type,
principalTable: "t_well_section_type",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
},
comment: "РТК бурение скважины");
migrationBuilder.CreateTable(
name: "t_process_map_well_ream",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
id_user = table.Column<int>(type: "integer", nullable: false, comment: "Id пользователя"),
id_well = table.Column<int>(type: "integer", nullable: false, comment: "Id скважины"),
id_wellsection_type = table.Column<int>(type: "integer", nullable: false, comment: "Тип секции"),
comment = table.Column<string>(type: "text", nullable: true, comment: "Комментарий"),
depth_end = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу до, м"),
depth_start = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу от, м"),
last_update = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата последнего изменения"),
pressure = table.Column<double>(type: "double precision", nullable: false, comment: "Давление, атм"),
repeats = table.Column<double>(type: "double precision", nullable: false, comment: "Количество повторений"),
setpoint_drag = table.Column<double>(type: "double precision", nullable: false, comment: "Уставка зятяжки, т"),
setpoint_tight = table.Column<double>(type: "double precision", nullable: false, comment: "Уставка посадки, т"),
speed_downward = table.Column<double>(type: "double precision", nullable: false, comment: "Скорость спуска, м/ч"),
speed_upward = table.Column<double>(type: "double precision", nullable: false, comment: "Скорость подъёма, м/ч"),
spin_downward = table.Column<double>(type: "double precision", nullable: false, comment: "Вращение при движении вниз, об/мин"),
spin_upward = table.Column<double>(type: "double precision", nullable: false, comment: "Вращение при движении вверх, об/мин"),
torque = table.Column<double>(type: "double precision", nullable: false, comment: "Момент, кН*м")
},
constraints: table =>
{
table.PrimaryKey("PK_t_process_map_well_ream", x => x.id);
table.ForeignKey(
name: "FK_t_process_map_well_ream_t_user_id_user",
column: x => x.id_user,
principalTable: "t_user",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_process_map_well_ream_t_well_id_well",
column: x => x.id_well,
principalTable: "t_well",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_process_map_well_ream_t_well_section_type_id_wellsection_~",
column: x => x.id_wellsection_type,
principalTable: "t_well_section_type",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
},
comment: "РТК проработка скважины");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_well_drilling_id_user",
table: "t_process_map_well_drilling",
column: "id_user");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_well_drilling_id_well",
table: "t_process_map_well_drilling",
column: "id_well");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_well_drilling_id_wellsection_type",
table: "t_process_map_well_drilling",
column: "id_wellsection_type");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_well_ream_id_user",
table: "t_process_map_well_ream",
column: "id_user");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_well_ream_id_well",
table: "t_process_map_well_ream",
column: "id_well");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_well_ream_id_wellsection_type",
table: "t_process_map_well_ream",
column: "id_wellsection_type");
}
}
}

View File

@ -317,6 +317,136 @@ namespace AsbCloudDb.Migrations
b.HasComment("Ежедневные отчёты");
});
modelBuilder.Entity("AsbCloudDb.Model.DataSaubStat", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<double>("AxialLoad")
.HasColumnType("double precision")
.HasColumnName("axial_load")
.HasComment("Фактическая нагрузка");
b.Property<double?>("AxialLoadLimitMax")
.HasColumnType("double precision")
.HasColumnName("axial_load_limit_max")
.HasComment("Максимально допустимая нагрузка");
b.Property<double?>("AxialLoadSp")
.HasColumnType("double precision")
.HasColumnName("axial_load_sp")
.HasComment("Ограничение факт. нагрузки");
b.Property<double?>("BlockSpeedSp")
.HasColumnType("double precision")
.HasColumnName("block_speed_sp")
.HasComment("Ограничение скорости блока");
b.Property<DateTimeOffset>("DateEnd")
.HasColumnType("timestamp with time zone")
.HasColumnName("date_end")
.HasComment("Дата и время окончания");
b.Property<DateTimeOffset>("DateStart")
.HasColumnType("timestamp with time zone")
.HasColumnName("date_start")
.HasComment("Дата и время начала");
b.Property<double>("DepthEnd")
.HasColumnType("double precision")
.HasColumnName("depth_end")
.HasComment("Глубина забоя по стволу конечная");
b.Property<double>("DepthStart")
.HasColumnType("double precision")
.HasColumnName("depth_start")
.HasComment("Глубина забоя по стволу начальная");
b.Property<int>("EnabledSubsystems")
.HasColumnType("integer")
.HasColumnName("enabled_subsystems")
.HasComment("Флаги подсистем");
b.Property<double>("Flow")
.HasColumnType("double precision")
.HasColumnName("flow")
.HasComment("Фактический расход");
b.Property<bool>("HasOscillation")
.HasColumnType("boolean")
.HasColumnName("has_oscillation")
.HasComment("Наличие или отсутствие осцилляции");
b.Property<int>("IdCategory")
.HasColumnType("integer")
.HasColumnName("id_category")
.HasComment("Название автоопределённой операции");
b.Property<short?>("IdFeedRegulator")
.HasColumnType("smallint")
.HasColumnName("id_feed_regulator")
.HasComment("Работа при достижении ограничения");
b.Property<int>("IdTelemetry")
.HasColumnType("integer")
.HasColumnName("id_telemetry")
.HasComment("Ключ телеметрии");
b.Property<double>("Pressure")
.HasColumnType("double precision")
.HasColumnName("pressure")
.HasComment("Давление");
b.Property<double?>("PressureIdle")
.HasColumnType("double precision")
.HasColumnName("pressure_idle")
.HasComment("Давление холостого хода");
b.Property<double?>("PressureSp")
.HasColumnType("double precision")
.HasColumnName("pressure_sp")
.HasComment("Ограничение фактического давления");
b.Property<double>("RotorSpeed")
.HasColumnType("double precision")
.HasColumnName("rotor_speed")
.HasComment("Фактическая скорость оборотов ВСП");
b.Property<double>("RotorTorque")
.HasColumnType("double precision")
.HasColumnName("rotor_torque")
.HasComment("Фактический момент");
b.Property<double?>("RotorTorqueLimitMax")
.HasColumnType("double precision")
.HasColumnName("rotor_torque_limit_max")
.HasComment("Максимально допустимый момент");
b.Property<double?>("RotorTorqueSp")
.HasColumnType("double precision")
.HasColumnName("rotor_torque_sp")
.HasComment("Ограничение факт. момента");
b.Property<double>("Speed")
.HasColumnType("double precision")
.HasColumnName("speed")
.HasComment("Скорость бурения");
b.HasKey("Id");
b.HasIndex("IdCategory");
b.HasIndex("IdTelemetry");
b.ToTable("t_data_saub_stat");
b.HasComment("Кеш-таблица для хранения данных для РТК-отчета");
});
modelBuilder.Entity("AsbCloudDb.Model.Deposit", b =>
{
b.Property<int>("Id")
@ -2617,29 +2747,20 @@ namespace AsbCloudDb.Migrations
b.HasComment("РТК план бурение");
});
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapWellDrilling", b =>
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapPlanReam", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
.HasColumnName("id")
.HasComment("Идентификатор");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<double>("AxialLoadLimitMax")
.HasColumnType("double precision")
.HasColumnName("axial_load_limit_max")
.HasComment("Нагрузка, допустимый максимум");
b.Property<double>("AxialLoadPlan")
.HasColumnType("double precision")
.HasColumnName("axial_load_plan")
.HasComment("Нагрузка, план");
b.Property<string>("Comment")
.HasColumnType("text")
.HasColumnName("comment")
.HasComment("Комментарий");
b.Property<DateTimeOffset>("Creation")
.HasColumnType("timestamp with time zone")
.HasColumnName("creation")
.HasComment("дата создания");
b.Property<double>("DepthEnd")
.HasColumnType("double precision")
@ -2651,25 +2772,25 @@ namespace AsbCloudDb.Migrations
.HasColumnName("depth_start")
.HasComment("Глубина по стволу от, м");
b.Property<double>("FlowLimitMax")
.HasColumnType("double precision")
.HasColumnName("flow_limit_max")
.HasComment("Расход, допустимый максимум");
b.Property<double>("FlowPlan")
.HasColumnType("double precision")
.HasColumnName("flow_plan")
.HasComment("Расход, план");
b.Property<int>("IdMode")
b.Property<int>("IdAuthor")
.HasColumnType("integer")
.HasColumnName("id_mode")
.HasComment("Id режима (1- ротор, 2 слайд)");
.HasColumnName("id_author")
.HasComment("Автор");
b.Property<int>("IdUser")
b.Property<int?>("IdEditor")
.HasColumnType("integer")
.HasColumnName("id_user")
.HasComment("Id пользователя");
.HasColumnName("id_editor")
.HasComment("Редактор");
b.Property<int?>("IdPrevious")
.HasColumnType("integer")
.HasColumnName("id_previous")
.HasComment("ИД состояния записи: \n0 - актуальная\n1 - замененная\n2 - удаленная");
b.Property<int>("IdState")
.HasColumnType("integer")
.HasColumnName("id_state")
.HasComment("ИД состояния записи: \n0 - актуальная\n1 - замененная\n2 - удаленная");
b.Property<int>("IdWell")
.HasColumnType("integer")
@ -2681,112 +2802,10 @@ namespace AsbCloudDb.Migrations
.HasColumnName("id_wellsection_type")
.HasComment("Тип секции");
b.Property<DateTimeOffset>("LastUpdate")
b.Property<DateTimeOffset?>("Obsolete")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_update")
.HasComment("Дата последнего изменения");
b.Property<double>("PressureLimitMax")
.HasColumnType("double precision")
.HasColumnName("pressure_limit_max")
.HasComment("Перепад давления, допустимый максимум");
b.Property<double>("PressurePlan")
.HasColumnType("double precision")
.HasColumnName("pressure_plan")
.HasComment("Перепад давления, план");
b.Property<double>("RopPlan")
.HasColumnType("double precision")
.HasColumnName("rop_plan")
.HasComment("Плановая механическая скорость, м/ч");
b.Property<double>("TopDriveSpeedLimitMax")
.HasColumnType("double precision")
.HasColumnName("top_drive_speed_limit_max")
.HasComment("Обороты на ВСП, допустимый максимум");
b.Property<double>("TopDriveSpeedPlan")
.HasColumnType("double precision")
.HasColumnName("top_drive_speed_plan")
.HasComment("Обороты на ВСП, план");
b.Property<double>("TopDriveTorqueLimitMax")
.HasColumnType("double precision")
.HasColumnName("top_drive_torque_limit_max")
.HasComment("Момент на ВСП, допустимый максимум");
b.Property<double>("TopDriveTorquePlan")
.HasColumnType("double precision")
.HasColumnName("top_drive_torque_plan")
.HasComment("Момент на ВСП, план");
b.Property<double>("UsageSaub")
.HasColumnType("double precision")
.HasColumnName("usage_saub")
.HasComment("Плановый процент использования АКБ");
b.Property<double>("UsageSpin")
.HasColumnType("double precision")
.HasColumnName("usage_spin")
.HasComment("Плановый процент использования spin master");
b.HasKey("Id");
b.HasIndex("IdUser");
b.HasIndex("IdWell");
b.HasIndex("IdWellSectionType");
b.ToTable("t_process_map_well_drilling");
b.HasComment("РТК бурение скважины");
});
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapWellReam", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Comment")
.HasColumnType("text")
.HasColumnName("comment")
.HasComment("Комментарий");
b.Property<double>("DepthEnd")
.HasColumnType("double precision")
.HasColumnName("depth_end")
.HasComment("Глубина по стволу до, м");
b.Property<double>("DepthStart")
.HasColumnType("double precision")
.HasColumnName("depth_start")
.HasComment("Глубина по стволу от, м");
b.Property<int>("IdUser")
.HasColumnType("integer")
.HasColumnName("id_user")
.HasComment("Id пользователя");
b.Property<int>("IdWell")
.HasColumnType("integer")
.HasColumnName("id_well")
.HasComment("Id скважины");
b.Property<int>("IdWellSectionType")
.HasColumnType("integer")
.HasColumnName("id_wellsection_type")
.HasComment("Тип секции");
b.Property<DateTimeOffset>("LastUpdate")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_update")
.HasComment("Дата последнего изменения");
.HasColumnName("obsolete")
.HasComment("дата устаревания");
b.Property<double>("Pressure")
.HasColumnType("double precision")
@ -2835,13 +2854,15 @@ namespace AsbCloudDb.Migrations
b.HasKey("Id");
b.HasIndex("IdUser");
b.HasIndex("IdAuthor");
b.HasIndex("IdEditor");
b.HasIndex("IdWell");
b.HasIndex("IdWellSectionType");
b.ToTable("t_process_map_well_ream");
b.ToTable("t_process_map_plan_ream");
b.HasComment("РТК проработка скважины");
});
@ -8292,6 +8313,25 @@ namespace AsbCloudDb.Migrations
b.Navigation("Well");
});
modelBuilder.Entity("AsbCloudDb.Model.DataSaubStat", b =>
{
b.HasOne("AsbCloudDb.Model.WellOperationCategory", "OperationCategory")
.WithMany()
.HasForeignKey("IdCategory")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AsbCloudDb.Model.Telemetry", "Telemetry")
.WithMany()
.HasForeignKey("IdTelemetry")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("OperationCategory");
b.Navigation("Telemetry");
});
modelBuilder.Entity("AsbCloudDb.Model.DetectedOperation", b =>
{
b.HasOne("AsbCloudDb.Model.WellOperationCategory", "OperationCategory")
@ -8593,14 +8633,18 @@ namespace AsbCloudDb.Migrations
b.Navigation("WellSectionType");
});
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapWellDrilling", b =>
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapPlanReam", b =>
{
b.HasOne("AsbCloudDb.Model.User", "User")
b.HasOne("AsbCloudDb.Model.User", "Author")
.WithMany()
.HasForeignKey("IdUser")
.HasForeignKey("IdAuthor")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AsbCloudDb.Model.User", "Editor")
.WithMany()
.HasForeignKey("IdEditor");
b.HasOne("AsbCloudDb.Model.Well", "Well")
.WithMany()
.HasForeignKey("IdWell")
@ -8613,34 +8657,9 @@ namespace AsbCloudDb.Migrations
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
b.Navigation("Author");
b.Navigation("Well");
b.Navigation("WellSectionType");
});
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapWellReam", b =>
{
b.HasOne("AsbCloudDb.Model.User", "User")
.WithMany()
.HasForeignKey("IdUser")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AsbCloudDb.Model.Well", "Well")
.WithMany()
.HasForeignKey("IdWell")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AsbCloudDb.Model.WellSectionType", "WellSectionType")
.WithMany()
.HasForeignKey("IdWellSectionType")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
b.Navigation("Editor");
b.Navigation("Well");

View File

@ -19,9 +19,8 @@ namespace AsbCloudDb.Model
public virtual DbSet<Deposit> Deposits => Set<Deposit>();
public virtual DbSet<DetectedOperation> DetectedOperations => Set<DetectedOperation>();
public virtual DbSet<TrajectoryPlan> TrajectoriesPlan => Set<TrajectoryPlan>();
public virtual DbSet<ProcessMapWellDrilling> ProcessMapWellDrillings => Set<ProcessMapWellDrilling>();
public virtual DbSet<ProcessMapWellReam> ProcessMapWellReams => Set<ProcessMapWellReam>();
public virtual DbSet<ProcessMapPlanDrilling> ProcessMapPlanDrilling => Set<ProcessMapPlanDrilling>();
public virtual DbSet<ProcessMapPlanReam> ProcessMapPlanReams => Set<ProcessMapPlanReam>();
public virtual DbSet<DrillingProgramPart> DrillingProgramParts => Set<DrillingProgramPart>();
public virtual DbSet<FileCategory> FileCategories => Set<FileCategory>();
public virtual DbSet<FileInfo> Files => Set<FileInfo>();
@ -90,6 +89,8 @@ namespace AsbCloudDb.Model
public DbSet<Contact> Contacts => Set<Contact>();
public DbSet<DrillTest> DrillTests => Set<DrillTest>();
public DbSet<DataSaubStat> DataSaubStat => Set<DataSaubStat>();
public AsbCloudDbContext() : base()
{
Interlocked.Increment(ref referenceCount);

View File

@ -0,0 +1,89 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace AsbCloudDb.Model
{
[Table("t_data_saub_stat"), Comment("Кеш-таблица для хранения данных для РТК-отчета")]
public class DataSaubStat : IId
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("date_start", TypeName = "timestamp with time zone"), Comment("Дата и время начала")]
public DateTimeOffset DateStart { get; set; }
[Column("date_end", TypeName = "timestamp with time zone"), Comment("Дата и время окончания")]
public DateTimeOffset DateEnd { get; set; }
[Column("depth_start"), Comment("Глубина забоя по стволу начальная")]
public double DepthStart { get; set; }
[Column("depth_end"), Comment("Глубина забоя по стволу конечная")]
public double DepthEnd { get; set; }
[Column("speed"), Comment("Скорость бурения")]
public double Speed { get; set; }
[Column("block_speed_sp"), Comment("Ограничение скорости блока")]
public double? BlockSpeedSp { get; set; }
[Column("pressure"), Comment("Давление")]
public double Pressure { get; set; }
[Column("pressure_idle"), Comment("Давление холостого хода")]
public double? PressureIdle { get; set; }
[Column("pressure_sp"), Comment("Ограничение фактического давления")]
public double? PressureSp { get; set; }
[Column("axial_load"), Comment("Фактическая нагрузка")]
public double AxialLoad { get; set; }
[Column("axial_load_sp"), Comment("Ограничение факт. нагрузки")]
public double? AxialLoadSp { get; set; }
[Column("axial_load_limit_max"), Comment("Максимально допустимая нагрузка")]
public double? AxialLoadLimitMax { get; set; }
[Column("rotor_torque"), Comment("Фактический момент")]
public double RotorTorque { get; set; }
[Column("rotor_torque_sp"), Comment("Ограничение факт. момента")]
public double? RotorTorqueSp { get; set; }
[Column("rotor_torque_limit_max"), Comment("Максимально допустимый момент")]
public double? RotorTorqueLimitMax { get; set; }
[Column("id_feed_regulator"), Comment("Работа при достижении ограничения")]
public short? IdFeedRegulator { get; set; }
[Column("rotor_speed"), Comment("Фактическая скорость оборотов ВСП")]
public double RotorSpeed { get; set; }
[Column("id_category"), Comment("Название автоопределённой операции")]
public int IdCategory { get; set; }
[Column("enabled_subsystems"), Comment("Флаги подсистем")]
public int EnabledSubsystems { get; set; }
[Column("has_oscillation"), Comment("Наличие или отсутствие осцилляции")]
public bool HasOscillation { get; set; }
[Column("flow"), Comment("Фактический расход")]
public double Flow { get; set; }
[Column("id_telemetry"), Comment("Ключ телеметрии")]
public int IdTelemetry { get; set; }
[ForeignKey(nameof(IdTelemetry))]
public virtual Telemetry Telemetry { get; set; } = null!;
[JsonIgnore]
[ForeignKey(nameof(IdCategory))]
public virtual WellOperationCategory OperationCategory { get; set; } = null!;
}
}

View File

@ -8,7 +8,7 @@ using System.Text.Json.Serialization;
namespace AsbCloudDb.Model
{
[Table("t_detected_operation"), Comment("автоматически определенные операции по телеметрии")]
public class DetectedOperation
public class DetectedOperation : IId
{
[Key]
[Column("id")]
@ -20,14 +20,14 @@ namespace AsbCloudDb.Model
[Column("id_category"), Comment("Id категории операции")]
public int IdCategory { get; set; }
[Column("id_user"), Comment("Id пользователя по телеметрии на момент начала операции")]
public int IdUsersAtStart { get; set; }
[Column("date_start", TypeName = "timestamp with time zone"), Comment("Дата начала операции")]
public DateTimeOffset DateStart { get; set; }
[Column("date_end", TypeName = "timestamp with time zone"), Comment("Дата начала операции")]
public DateTimeOffset DateEnd { get; set; }
[Column("id_user"), Comment("Id пользователя по телеметрии на момент начала операции")]
public int IdUsersAtStart { get; set; }
[NotMapped]
public double DurationMinutes => (DateEnd - DateStart).TotalMinutes;

View File

@ -23,8 +23,6 @@ namespace AsbCloudDb.Model
DbSet<Deposit> Deposits { get; }
DbSet<DetectedOperation> DetectedOperations { get; }
DbSet<TrajectoryPlan> TrajectoriesPlan { get; }
DbSet<ProcessMapWellDrilling> ProcessMapWellDrillings { get; }
DbSet<ProcessMapWellReam> ProcessMapWellReams { get; }
DbSet<DrillingProgramPart> DrillingProgramParts { get; }
DbSet<FileCategory> FileCategories { get; }
DbSet<FileInfo> Files { get; }
@ -80,7 +78,9 @@ namespace AsbCloudDb.Model
DbSet<DrillTest> DrillTests { get; }
DbSet<TrajectoryFact> TrajectoriesFact { get; }
DbSet<WellSectionPlan> WellSectionsPlan { get; }
DbSet<DataSaubStat> DataSaubStat { get; }
DatabaseFacade Database { get; }
DbSet<ProcessMapPlanReam> ProcessMapPlanReams { get; }
Task<int> RefreshMaterializedViewAsync(string mwName, CancellationToken token);
Task<int> RefreshMaterializedViewAsync<TEntity>(CancellationToken token) where TEntity : class;

View File

@ -1,10 +1,11 @@
using System.ComponentModel.DataAnnotations.Schema;
using AsbCloudDb.Model.ProcessMapPlan;
using Microsoft.EntityFrameworkCore;
namespace AsbCloudDb.Model.ProcessMaps;
[Table("t_process_map_well_ream"), Comment("РТК проработка скважины")]
public class ProcessMapWellReam : ProcessMapBase
[Table("t_process_map_plan_ream"), Comment("РТК проработка скважины")]
public class ProcessMapPlanReam : ProcessMapPlanBase
{
[Column("repeats"), Comment("Количество повторений")]
public double Repeats { get; set; }

View File

@ -1,43 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model.ProcessMaps;
public abstract class ProcessMapBase : IId, IWellRelated
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("id_well"), Comment("Id скважины")]
public int IdWell { get; set; }
[Column("id_wellsection_type"), Comment("Тип секции")]
public int IdWellSectionType { get; set; }
[Column("id_user"), Comment("Id пользователя")]
public int IdUser { get; set; }
[Column("last_update", TypeName = "timestamp with time zone"), Comment("Дата последнего изменения")]
public DateTimeOffset LastUpdate { get; set; }
[Column("depth_start"), Comment("Глубина по стволу от, м")]
public double DepthStart { get; set; }
[Column("depth_end"), Comment("Глубина по стволу до, м")]
public double DepthEnd { get; set; }
[Column("comment"), Comment("Комментарий")]
public string? Comment { get; set; }
[ForeignKey(nameof(IdWell))]
public virtual Well Well { get; set; } = null!;
[ForeignKey(nameof(IdUser))]
public virtual User User { get; set; } = null!;
[ForeignKey(nameof(IdWellSectionType))]
public virtual WellSectionType WellSectionType { get; set; } = null!;
}

View File

@ -1,50 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model.ProcessMaps;
[Table("t_process_map_well_drilling"), Comment("РТК бурение скважины")]
public class ProcessMapWellDrilling : ProcessMapBase
{
[Column("id_mode"), Comment("Id режима (1- ротор, 2 слайд)")]
public int IdMode { get; set; }
[Column("axial_load_plan"), Comment("Нагрузка, план")]
public double AxialLoadPlan { get; set; }
[Column("axial_load_limit_max"), Comment("Нагрузка, допустимый максимум")]
public double AxialLoadLimitMax { get; set; }
[Column("pressure_plan"), Comment("Перепад давления, план")]
public double PressurePlan { get; set; }
[Column("pressure_limit_max"), Comment("Перепад давления, допустимый максимум")]
public double PressureLimitMax { get; set; }
[Column("top_drive_torque_plan"), Comment("Момент на ВСП, план")]
public double TopDriveTorquePlan { get; set; }
[Column("top_drive_torque_limit_max"), Comment("Момент на ВСП, допустимый максимум")]
public double TopDriveTorqueLimitMax { get; set; }
[Column("top_drive_speed_plan"), Comment("Обороты на ВСП, план")]
public double TopDriveSpeedPlan { get; set; }
[Column("top_drive_speed_limit_max"), Comment("Обороты на ВСП, допустимый максимум")]
public double TopDriveSpeedLimitMax { get; set; }
[Column("flow_plan"), Comment("Расход, план")]
public double FlowPlan { get; set; }
[Column("flow_limit_max"), Comment("Расход, допустимый максимум")]
public double FlowLimitMax { get; set; }
[Column("rop_plan"), Comment("Плановая механическая скорость, м/ч")]
public double RopPlan { get; set; }
[Column("usage_saub"), Comment("Плановый процент использования АКБ")]
public double UsageSaub { get; set; }
[Column("usage_spin"), Comment("Плановый процент использования spin master")]
public double UsageSpin { get; set; }
}

View File

@ -67,6 +67,23 @@ namespace AsbCloudDb.Model
[JsonIgnore]
[ForeignKey(nameof(IdPlan))]
public virtual WellOperation? OperationPlan { get; set; } = null!;
public bool IsSame(WellOperation other)
{
var isSame = IdWell == other.IdWell &&
IdWellSectionType == other.IdWellSectionType &&
IdCategory == other.IdCategory &&
IdType == other.IdType &&
IdPlan == other.IdPlan &&
DepthStart == other.DepthStart &&
DepthEnd == other.DepthEnd &&
DateStart == other.DateStart &&
DurationHours == other.DurationHours &&
CategoryInfo == other.CategoryInfo &&
Comment == other.Comment;
return isSame;
}
}
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
@ -14,6 +14,8 @@
<None Remove="CommonLibs\Readme.md" />
<None Remove="Services\DailyReport\DailyReportTemplate.xlsx" />
<None Remove="Services\DrillTestReport\DrillTestReportTemplate.xlsx" />
<None Remove="Services\ProcessMapPlan\Templates\ProcessMapPlanReamTemplate.xlsx" />
<None Remove="Services\ProcessMaps\Report\ProcessMapReportDataSaubStatTemplate.xlsx" />
<None Remove="Services\Trajectory\FactTrajectoryTemplate.xlsx" />
<None Remove="Services\Trajectory\NnbTrajectoryTemplate.xlsx" />
<None Remove="Services\Trajectory\PlannedTrajectoryTemplate.xlsx" />
@ -36,6 +38,9 @@
<EmbeddedResource Include="Services\DetectOperations\DetectOperations.xlsx" />
<EmbeddedResource Include="Services\DailyReport\DailyReportTemplate.xlsx" />
<EmbeddedResource Include="Services\DrillTestReport\DrillTestReportTemplate.xlsx" />
<EmbeddedResource Include="Services\ProcessMapPlan\Templates\ProcessMapPlanReamTemplate.xlsx" />
<EmbeddedResource Include="Services\ProcessMapPlan\Templates\ProcessMapPlanDrillingTemplate.xlsx" />
<EmbeddedResource Include="Services\ProcessMaps\Report\ProcessMapReportDataSaubStatTemplate.xlsx" />
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryFactNnbTemplate.xlsx" />
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryFactManualTemplate.xlsx" />
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryPlanTemplate.xlsx" />
@ -45,7 +50,6 @@
<EmbeddedResource Include="Services\WellOperationImport\Files\Dictionaries\Sections.txt" />
<EmbeddedResource Include="Services\WellOperationImport\Files\Dictionaries\OperationAttributes.txt" />
<EmbeddedResource Include="Services\ProcessMaps\Report\ProcessMapReportTemplate.xlsx" />
<EmbeddedResource Include="Services\ProcessMaps\WellDrilling\ProcessMapPlanImportWellDrillingTemplate.xlsx" />
</ItemGroup>
<ItemGroup>
@ -53,7 +57,7 @@
<PackageReference Include="AsbSaubReportLas" Version="3.24.116.510" />
<PackageReference Include="AsbSaubReportPdf" Version="3.24.116.510" />
<PackageReference Include="CliWrap" Version="3.6.6" />
<PackageReference Include="ClosedXML" Version="0.97.0" />
<PackageReference Include="ClosedXML" Version="0.102.2" />
<PackageReference Include="itext7" Version="8.0.2" />
<PackageReference Include="itext7.bouncy-castle-adapter" Version="8.0.2" />
<PackageReference Include="Mapster" Version="7.4.0" />

View File

@ -1,30 +1,50 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure
{
public static class AssemblyExtensions
{
public static async Task<Stream> GetTemplateCopyStreamAsync(this Assembly assembly, string templateName, CancellationToken cancellationToken)
{
var resourceName = assembly
.GetManifestResourceNames()
.FirstOrDefault(n => n.EndsWith(templateName))!;
public static class AssemblyExtensions
{
public static Stream GetTemplateCopyStream(this Assembly assembly, string templateName)
{
var resourceName = assembly
.GetManifestResourceNames()
.FirstOrDefault(n => n.EndsWith(templateName));
using var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName)!;
if (string.IsNullOrWhiteSpace(resourceName))
throw new ArgumentNullException(nameof(resourceName));
var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream, cancellationToken);
memoryStream.Position = 0;
using var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName);
return memoryStream;
}
}
}
var memoryStream = new MemoryStream();
stream?.CopyTo(memoryStream);
memoryStream.Position = 0;
return memoryStream;
}
[Obsolete]
public static async Task<Stream> GetTemplateCopyStreamAsync(this Assembly assembly,
string templateName,
CancellationToken cancellationToken)
{
var resourceName = assembly
.GetManifestResourceNames()
.FirstOrDefault(n => n.EndsWith(templateName))!;
using var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName)!;
var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream, cancellationToken);
memoryStream.Position = 0;
return memoryStream;
}
}
}

View File

@ -0,0 +1,239 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.DetectOperations;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Background.PeriodicWorks
{
/// <summary>
/// задача по добавлению данных в таблицу DataSaubStat, которая используется дл построения РТК-отчета
/// </summary>
internal class WorkDataSaubStat : Work
{
private int Gap = 60;
public WorkDataSaubStat() : base("Generate DataSaubStat entries and save them into Db")
{
Timeout = TimeSpan.FromMinutes(10);
}
protected override async Task Action(string id, IServiceProvider services, Action<string, double?> onProgressCallback, CancellationToken token)
{
var telemetryDataCache = services.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
var cacheRequest = new TelemetryDataRequest()
{
GeDate = DateTime.UtcNow.AddDays(-Gap)
};
var idTelemetries = telemetryDataCache.GetIds(cacheRequest).ToArray();
if (!idTelemetries.Any())
return;
var dataSaubStatRepo = services.GetRequiredService<IDataSaubStatRepository>();
var dataSaubService = services.GetRequiredService<ITelemetryDataSaubService>();
var detectedOperationRepository = services.GetRequiredService<IDetectedOperationRepository>();
var stats = await dataSaubStatRepo.GetLastsAsync(idTelemetries, token);
for( var i =0; i < idTelemetries.Length; i++)
{
var idTelemetry = idTelemetries[i];
var lastDate = stats.FirstOrDefault(s => s.IdTelemetry == idTelemetry)?.DateEnd.ToUniversalTime() ?? DateTimeOffset.UnixEpoch;
var statsCount = await CreateStatForTelemetryFromDate(idTelemetry, lastDate, dataSaubService, dataSaubStatRepo, detectedOperationRepository, token);
onProgressCallback($"Calculate stat for telemetry: {idTelemetry}; from {lastDate}; results count: {statsCount};", 100*i / idTelemetries.Length);
}
}
private static async Task<int> CreateStatForTelemetryFromDate(
int idTelemetry,
DateTimeOffset begin,
ITelemetryDataSaubService dataSaubService,
IDataSaubStatRepository dataSaubStatRepo,
IDetectedOperationRepository detectedOperationRepository,
CancellationToken token)
{
var detectedOperationRequest = new DetectedOperationByTelemetryRequest {
GeDateStart = begin,
IdTelemetry = idTelemetry,
IdsCategories = WellOperationCategory.MechanicalDrillingSubIds,
SortFields = new[] {nameof(DetectedOperation.DateStart) },
Take = 250,
};
var detectedOperations = await detectedOperationRepository.Get(detectedOperationRequest, token);
if (!detectedOperations.Any())
return 0;
var geDate = detectedOperations.First().DateStart;
var leDate = detectedOperations.OrderByDescending(d => d.DateEnd).First().DateEnd;
var dataSaub = await dataSaubService.Get(idTelemetry, true, geDate, leDate, 100_000, token);
if (!dataSaub.Any())
return 0;
if(dataSaub is not TelemetryDataSaubDto[] dataSaubArray)
dataSaubArray = dataSaub.ToArray();
var dataSaubStats = CreateDataSaubStat(detectedOperations, dataSaubArray);
return await dataSaubStatRepo.InsertRangeAsync(dataSaubStats, token);
}
private static IEnumerable<DataSaubStatDto> CreateDataSaubStat(IEnumerable<DetectedOperationDto> detectedOperations, TelemetryDataSaubDto[] dataSaub)
{
var indexStart = 0;
var indexEnd = 0;
var result = new List<DataSaubStatDto>();
if (!dataSaub.Any())
return result;
foreach (var operation in detectedOperations)
{
indexStart = Array.FindIndex(dataSaub, indexEnd, t => t.DateTime >= operation.DateStart);
if (indexStart < 0)
break;
indexEnd = Array.FindIndex(dataSaub, indexStart, t => t.DateTime > operation.DateEnd);
if (indexEnd < 0)
indexEnd = dataSaub.Length - 1;
if (indexEnd == indexStart)
continue;
var length = indexEnd - indexStart;
var subset = dataSaub.AsSpan(indexStart, length);
var stats = CalcStats(operation, subset);
result.AddRange(stats);
}
return result;
}
private static IEnumerable<DataSaubStatDto> CalcStats(DetectedOperationDto operation, Span<TelemetryDataSaubDto> dataSaub)
{
var result = new List<DataSaubStatDto>();
var indexStart = 0;
for (var i = 1; i < dataSaub.Length; i++)
{
var previous = dataSaub[i - 1];
var current = dataSaub[i];
if (IsNewCacheItem(previous, current) || i == dataSaub.Length - 1)
{
var length = i - indexStart;
var span = dataSaub.Slice(indexStart, length);
indexStart = i;
if (length <= 2 || (span[^1].WellDepth - span[0].WellDepth) < 0.001)
continue; // мелкие выборки не учитываем.
var stat = CalcStat(operation, span);
result.Add(stat);
}
}
return result;
}
private static DataSaubStatDto CalcStat(DetectedOperationDto operation, Span<TelemetryDataSaubDto> span)
{
var hasOscillation = EnabledSubsystemsFlags.AutoOscillation.HasEnabledSubsystems(operation.EnabledSubsystems);
var aggregatedValues = CalcAggregate(span);
var dateStart = span[0].DateTime;
var dateEnd = span[^1].DateTime;
var depthStart = span[0].WellDepth;
var depthEnd = span[^1].WellDepth;
var speed = ((depthEnd - depthStart) / (dateEnd - dateStart).TotalHours);
var processMapDrillingCacheItem = new DataSaubStatDto
{
DateStart = dateStart,
DateEnd = dateEnd,
DepthStart = depthStart,
DepthEnd = depthEnd,
Speed = speed,
BlockSpeedSp = span[0].BlockSpeedSp,
Pressure = aggregatedValues.Pressure,
PressureIdle = span[0].PressureIdle,
PressureSp = span[0].PressureSp,
AxialLoad = aggregatedValues.AxialLoad,
AxialLoadSp = span[0].AxialLoadSp,
AxialLoadLimitMax = span[0].AxialLoadLimitMax,
RotorTorque = aggregatedValues.RotorTorque,
RotorTorqueSp = span[0].RotorTorqueSp,
RotorTorqueLimitMax = span[0].RotorTorqueLimitMax,
IdFeedRegulator = span[0].IdFeedRegulator,
RotorSpeed = aggregatedValues.RotorSpeed,
IdCategory = operation.IdCategory,
EnabledSubsystems = operation.EnabledSubsystems,
HasOscillation = hasOscillation,
IdTelemetry = operation.IdTelemetry,
Flow = aggregatedValues.Flow
};
return processMapDrillingCacheItem;
}
private static (
double Pressure,
double AxialLoad,
double RotorTorque,
double RotorSpeed,
double Flow
) CalcAggregate(Span<TelemetryDataSaubDto> span)
{
var sumPressure = 0.0;
var sumAxialLoad = 0.0;
var sumRotorTorque = 0.0;
var sumRotorSpeed = 0.0;
var flow = span[0].Flow ?? 0.0;
var diffDepthTotal = span[^1].WellDepth - span[0].WellDepth;
for (var i = 0; i < span.Length - 1; i++)
{
var diffDepth = span[i + 1].WellDepth - span[i].WellDepth;
sumPressure += diffDepth * span[i].Pressure;
sumAxialLoad += diffDepth * span[i].AxialLoad;
sumRotorTorque += diffDepth * span[i].RotorTorque;
sumRotorSpeed += diffDepth * span[i].RotorSpeed;
flow = span[i + 1].Flow > flow ? span[i + 1].Flow ?? 0.0 : flow;
}
return (
Pressure: sumPressure / diffDepthTotal,
AxialLoad: sumAxialLoad / diffDepthTotal,
RotorTorque: sumRotorTorque / diffDepthTotal,
RotorSpeed: sumRotorSpeed / diffDepthTotal,
Flow: flow
);
}
private static bool IsNewCacheItem(TelemetryDataSaubDto previous, TelemetryDataSaubDto current)
{
return !(current.Mode == previous.Mode)
|| !(current.WellDepth >= previous.WellDepth)
|| !(current.BlockSpeedSp == previous.BlockSpeedSp)
|| !(current.PressureIdle == previous.PressureIdle)
|| !(current.PressureSp == previous.PressureSp)
|| !(current.AxialLoadSp == previous.AxialLoadSp)
|| !(current.AxialLoadLimitMax == previous.AxialLoadLimitMax)
|| !(current.HookWeightIdle == previous.HookWeightIdle)
|| !(current.RotorTorqueIdle == previous.RotorTorqueIdle)
|| !(current.RotorTorqueSp == previous.RotorTorqueSp)
|| !(current.RotorTorqueLimitMax == previous.RotorTorqueLimitMax)
|| !(current.IdFeedRegulator == previous.IdFeedRegulator);
}
}
}

View File

@ -1,5 +1,5 @@
using System;
using AsbCloudApp.Data;
using AsbCloudApp.Data;
using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance;
using AsbCloudApp.Data.DrillTestReport;
using AsbCloudApp.Data.Manuals;
using AsbCloudApp.Data.ProcessMaps;
@ -8,15 +8,19 @@ using AsbCloudApp.Data.Subsystems;
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Data.WellOperationImport.Options;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudApp.Services.DailyReport;
using AsbCloudApp.Services.Notifications;
using AsbCloudApp.Services.ProcessMaps;
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using AsbCloudApp.Services.WellOperationImport;
using AsbCloudDb.Model;
using AsbCloudDb.Model.DailyReports.Blocks.TimeBalance;
using AsbCloudDb.Model.Manuals;
using AsbCloudDb.Model.ProcessMaps;
using AsbCloudDb.Model.Trajectory;
using AsbCloudDb.Model.WellSections;
using AsbCloudInfrastructure.Background;
using AsbCloudInfrastructure.Repository;
using AsbCloudInfrastructure.Services;
@ -24,13 +28,14 @@ using AsbCloudInfrastructure.Services.DailyReport;
using AsbCloudInfrastructure.Services.DetectOperations;
using AsbCloudInfrastructure.Services.DrillingProgram;
using AsbCloudInfrastructure.Services.DrillTestReport;
using AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
using AsbCloudInfrastructure.Services.ProcessMaps;
using AsbCloudInfrastructure.Services.ProcessMaps.Report;
using AsbCloudInfrastructure.Services.ProcessMaps.WellDrilling;
using AsbCloudInfrastructure.Services.SAUB;
using AsbCloudInfrastructure.Services.Subsystems;
using AsbCloudInfrastructure.Services.Trajectory;
using AsbCloudInfrastructure.Services.Trajectory.Export;
using AsbCloudInfrastructure.Services.Trajectory.Import;
using AsbCloudInfrastructure.Services.Trajectory.Parser;
using AsbCloudInfrastructure.Services.WellOperationImport;
using AsbCloudInfrastructure.Services.WellOperationImport.FileParser;
using AsbCloudInfrastructure.Services.WellOperationService;
@ -39,13 +44,8 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance;
using AsbCloudApp.Services.DailyReport;
using AsbCloudDb.Model.DailyReports.Blocks.TimeBalance;
using AsbCloudDb.Model.WellSections;
using AsbCloudInfrastructure.Services.ProcessMaps;
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Requests;
using System;
using AsbCloudInfrastructure.Services.ProcessMapPlan.Export;
namespace AsbCloudInfrastructure
{
@ -53,6 +53,10 @@ namespace AsbCloudInfrastructure
{
public static void MapsterSetup()
{
TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<ScheduleDto, Schedule>()
.Ignore(source => source.Driller);
TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<DateTimeOffset, DateTime>()
.MapWith((source) => source.DateTime);
@ -101,61 +105,19 @@ namespace AsbCloudInfrastructure
.Ignore(dst => dst.NotificationCategory,
dst => dst.User);
TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<ProcessMapWellDrilling, ProcessMapPlanWellDrillingDto>()
.Map(dest => dest.AxialLoad, src => new PlanLimitDto
{
LimitMax = src.AxialLoadLimitMax,
Plan = src.AxialLoadPlan
})
.Map(dest => dest.Flow, src => new PlanLimitDto
{
LimitMax = src.FlowLimitMax,
Plan = src.FlowPlan
})
.Map(dest => dest.Pressure, src => new PlanLimitDto
{
LimitMax = src.PressureLimitMax,
Plan = src.PressurePlan
})
.Map(dest => dest.TopDriveSpeed, src => new PlanLimitDto
{
LimitMax = src.TopDriveSpeedLimitMax,
Plan = src.TopDriveSpeedPlan
})
.Map(dest => dest.TopDriveTorque, src => new PlanLimitDto
{
LimitMax = src.TopDriveTorqueLimitMax,
Plan = src.TopDriveTorquePlan
});
TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<ProcessMapPlanWellDrillingDto, ProcessMapWellDrilling>()
.Map(dest => dest.AxialLoadPlan, src => src.AxialLoad.Plan)
.Map(dest => dest.AxialLoadLimitMax, src => src.AxialLoad.LimitMax)
.Map(dest => dest.FlowPlan, src => src.Flow.Plan)
.Map(dest => dest.FlowLimitMax, src => src.Flow.LimitMax)
.Map(dest => dest.PressurePlan, src => src.Pressure.Plan)
.Map(dest => dest.PressureLimitMax, src => src.Pressure.LimitMax)
.Map(dest => dest.TopDriveSpeedPlan, src => src.TopDriveSpeed.Plan)
.Map(dest => dest.TopDriveSpeedLimitMax, src => src.TopDriveSpeed.LimitMax)
.Map(dest => dest.TopDriveTorquePlan, src => src.TopDriveTorque.Plan)
.Map(dest => dest.TopDriveTorqueLimitMax, src => src.TopDriveTorque.LimitMax);
TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<TimeBalanceRecord, TimeBalanceRecordDto>()
.Map(dest => dest.DurationHours, src => new PlanFactDto<double?>()
{
Plan = src.DurationHoursPlan,
Fact = src.DurationHoursFact
Plan = src.DurationHoursPlan,
Fact = src.DurationHoursFact
});
TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<TimeBalanceBlock, TimeBalanceBlockDto>()
.Map(dest => dest.WellDepth, src => new PlanFactDto<double?>()
{
Plan = src.WellDepthPlan
Plan = src.WellDepthPlan
});
}
@ -185,8 +147,6 @@ namespace AsbCloudInfrastructure
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
services.AddTransient<IAuthService, AuthService>();
services.AddTransient<IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto>, ProcessMapPlanRepository<ProcessMapPlanWellDrillingDto, ProcessMapWellDrilling>>();
services.AddTransient<IProcessMapPlanRepository<ProcessMapPlanWellReamDto>, ProcessMapPlanRepository<ProcessMapPlanWellReamDto, ProcessMapWellReam>>();
services.AddTransient<IDepositRepository, DepositRepository>();
services.AddTransient<IDrillingProgramService, DrillingProgramService>();
services.AddTransient<IEventService, EventService>();
@ -201,12 +161,7 @@ namespace AsbCloudInfrastructure
services.AddTransient<ITimezoneService, TimezoneService>();
services.AddScoped<IWellService, WellService>();
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
services.AddTransient<IProcessMapReportWellDrillingExportService, ProcessMapReportWellDrillingExportService>();
services.AddTransient<TrajectoryPlanExportService>();
services.AddTransient<TrajectoryFactManualExportService>();
services.AddTransient<TrajectoryFactNnbExportService>();
services.AddTransient<TrajectoryPlanParserService>();
services.AddTransient<TrajectoryFactManualParserService>();
services.AddTransient<IProcessMapReportDrillingExportService, ProcessMapReportDataSaubStatExportService>();
services.AddTransient<IWellOperationRepository, WellOperationRepository>();
services.AddTransient<IDailyReportService, DailyReportService>();
services.AddTransient<IDetectedOperationService, DetectedOperationService>();
@ -217,16 +172,21 @@ namespace AsbCloudInfrastructure
services.AddTransient<IWellFinalDocumentsService, WellFinalDocumentsService>();
services.AddTransient<IFileCategoryService, FileCategoryService>();
services.AddTransient<ILimitingParameterService, LimitingParameterService>();
services.AddTransient<IProcessMapReportWellDrillingService, ProcessMapReportWellDrillingService>();
services.AddTransient<IProcessMapPlanImportService, ProcessMapPlanImportWellDrillingService>();
services.AddTransient<WellInfoService>();
services.AddTransient<IHelpPageService, HelpPageService>();
services.AddTransient<IScheduleReportService, ScheduleReportService>();
services.AddTransient<IDataSaubStatRepository, DataSaubStatRepository>();
services.AddTransient<
IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell>,
IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell>,
ProcessMapPlanBaseRepository<ProcessMapPlanDrillingDto, ProcessMapPlanDrilling>>();
services.AddTransient<
IChangeLogRepository<ProcessMapPlanReamDto, ProcessMapPlanBaseRequestWithWell>,
ProcessMapPlanBaseRepository<ProcessMapPlanReamDto, ProcessMapPlanReam>>();
services.AddTransient<IProcessMapReportDrillingService, ProcessMapReportDrillingService>();
services.AddTransient<TrajectoryService>();
services.AddTransient<IGtrRepository, GtrWitsRepository>();
@ -236,6 +196,7 @@ namespace AsbCloudInfrastructure
services.AddTransient<ICrudRepository<NotificationCategoryDto>, CrudCacheRepositoryBase<NotificationCategoryDto,
NotificationCategory>>();
services.AddTransient<IDrillTestRepository, DrillTestRepository>();
services.AddTransient<IWellCompositeOperationService, WellCompositeOperationService>();
// admin crud services:
services.AddTransient<ICrudRepository<TelemetryDto>, CrudCacheRepositoryBase<TelemetryDto, Telemetry>>(s =>
@ -299,7 +260,7 @@ namespace AsbCloudInfrastructure
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record50Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record50Dto, AsbCloudDb.Model.WITS.Record50>>();
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record60Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record60Dto, AsbCloudDb.Model.WITS.Record60>>();
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record61Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record61Dto, AsbCloudDb.Model.WITS.Record61>>();
services.AddTransient<IDrillTestReportService, DrillTestReportService>();
services.AddTransient<IReportMakerService<DrillTestReportDataDto>, DrillTestReportMakerService>();
@ -321,13 +282,24 @@ namespace AsbCloudInfrastructure
services.AddTransient<IDailyReportService, DailyReportService>();
services.AddTransient<IDailyReportRepository, DailyReportRepository>();
services.AddTransient<IDailyReportExportService, DailyReportExportService>();
services.AddTransient<IRepositoryWellRelated<WellSectionPlanDto>, CrudWellRelatedRepositoryBase<WellSectionPlanDto, WellSectionPlan>>();
services.AddTransient<IProcessMapPlanService<ProcessMapPlanWellDrillingDto>, ProcessMapPlanService<ProcessMapPlanWellDrillingDto>>();
services.AddTransient<IProcessMapPlanService<ProcessMapPlanWellReamDto>, ProcessMapPlanService<ProcessMapPlanWellReamDto>>();
services.AddTransient<IWellSectionPlanRepository, WellSectionPlanRepository>();
services.AddTransient<IWellOperationCategoryRepository, WellOperationCategoryRepository>();
services.AddTransient<IDetectedOperationRepository, DetectedOperationRepository>();
services.AddTransient<TrajectoryPlanParser>();
services.AddTransient<TrajectoryFactManualParser>();
services.AddTransient<ProcessMapPlanDrillingParser>();
services.AddTransient<ProcessMapPlanReamParser>();
services.AddTransient<TrajectoryPlanExportService>();
services.AddTransient<TrajectoryFactManualExportService>();
services.AddTransient<TrajectoryFactNnbExportService>();
services.AddTransient<ProcessMapPlanDrillingExportService>();
services.AddTransient<ProcessMapPlanReamExportService>();
return services;
}

View File

@ -18,11 +18,11 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
where TEntity : ChangeLogAbstract
where TRequest : ChangeLogBaseRequest
{
protected readonly IAsbCloudDbContext context;
protected readonly IAsbCloudDbContext db;
public ChangeLogRepositoryAbstract(IAsbCloudDbContext context)
public ChangeLogRepositoryAbstract(IAsbCloudDbContext db)
{
this.context = context;
this.db = db;
}
public async Task<int> InsertRange(int idUser, IEnumerable<TDto> dtos, CancellationToken token)
@ -32,7 +32,7 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
{
var entities = dtos.Select(Convert);
var creation = DateTimeOffset.UtcNow;
var dbSet = context.Set<TEntity>();
var dbSet = db.Set<TEntity>();
foreach (var entity in entities)
{
entity.Id = default;
@ -62,9 +62,8 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
var ids = dtos.Select(d => d.Id);
using var transaction = context.Database.BeginTransaction();
var result = 0;
var dbSet = context
var dbSet = db
.Set<TEntity>();
var entitiesToDelete = await dbSet
@ -80,30 +79,40 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
throw new ArgumentInvalidException(nameof(dtos), $"записи с id:[{stringnotFoundIds}] не найдены, или не актуальны.");
}
foreach (var entity in entitiesToDelete)
using var transaction = db.Database.BeginTransaction();
try
{
entity.IdState = ChangeLogAbstract.IdStateReplaced;
entity.Obsolete = updateTime;
entity.IdEditor = idUser;
}
result += await context.SaveChangesAsync(token);
foreach (var entity in entitiesToDelete)
{
entity.IdState = ChangeLogAbstract.IdStateReplaced;
entity.Obsolete = updateTime;
entity.IdEditor = idUser;
}
result += await db.SaveChangesAsync(token);
var entitiesNew = dtos.Select(Convert);
foreach (var entity in entitiesNew)
var entitiesNew = dtos.Select(Convert);
foreach (var entity in entitiesNew)
{
entity.IdPrevious = entity.Id;
entity.Id = default;
entity.Creation = updateTime;
entity.IdAuthor = idUser;
entity.Obsolete = null;
entity.IdEditor = null;
entity.IdState = ChangeLogAbstract.IdStateActual;
dbSet.Add(entity);
}
result += await SaveChangesWithExceptionHandling(token);
await transaction.CommitAsync(token);
return result;
}
catch
{
entity.IdPrevious = entity.Id;
entity.Id = default;
entity.Creation = updateTime;
entity.IdAuthor = idUser;
entity.Obsolete = null;
entity.IdEditor = null;
entity.IdState = ChangeLogAbstract.IdStateActual;
dbSet.Add(entity);
await transaction.RollbackAsync(token);
throw;
}
result += await SaveChangesWithExceptionHandling(token);
await transaction.CommitAsync(token);
return result;
}
public async Task<int> UpdateOrInsertRange(int idUser, IEnumerable<TDto> dtos, CancellationToken token)
@ -143,17 +152,26 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
public async Task<int> ClearAndInsertRange(int idUser, TRequest request, IEnumerable<TDto> dtos, CancellationToken token)
{
var result = 0;
var transaction = await context.Database.BeginTransactionAsync(token);
result += await Clear(idUser, request, token);
result += await InsertRange(idUser, dtos, token);
await transaction.CommitAsync(token);
return result;
using var transaction = await db.Database.BeginTransactionAsync(token);
try
{
result += await Clear(idUser, request, token);
result += await InsertRange(idUser, dtos, token);
await transaction.CommitAsync(token);
return result;
}
catch
{
await transaction.RollbackAsync(token);
throw;
}
}
public async Task<int> DeleteRange(int idUser, IEnumerable<int> ids, CancellationToken token)
{
var updateTime = DateTimeOffset.UtcNow;
var query = context.Set<TEntity>()
var query = db.Set<TEntity>()
.Where(e => ids.Contains(e.Id))
.Where(e => e.Obsolete == null);
@ -269,7 +287,7 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
{
try
{
var result = await context.SaveChangesAsync(token);
var result = await db.SaveChangesAsync(token);
return result;
}
catch (DbUpdateException ex)

View File

@ -43,5 +43,4 @@ namespace AsbCloudInfrastructure.Repository
return dtos;
}
}
}

View File

@ -0,0 +1,85 @@
using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository
{
public class DataSaubStatRepository : IDataSaubStatRepository
{
private readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService;
public DataSaubStatRepository(IAsbCloudDbContext dbContext, ITelemetryService telemetryService)
{
db = dbContext;
this.telemetryService = telemetryService;
}
public async Task<IEnumerable<DataSaubStatDto>> GetLastsAsync(int[] idTelemetries, CancellationToken token)
{
var timeZoneOffsets = idTelemetries
.Distinct()
.ToDictionary(idTelemetry => idTelemetry, idTelemetry => TimeSpan.FromHours(telemetryService.GetTimezone(idTelemetry).Hours));
var stats = await db.Set<DataSaubStat>()
.Where(s => idTelemetries.Contains(s.IdTelemetry))
.GroupBy(s => s.IdTelemetry, (key, group) => group.OrderByDescending(el => el.DateEnd).First())
.ToArrayAsync(token);
var result = stats.Select(s => ConvertToDto(s, timeZoneOffsets[s.IdTelemetry]));
return result;
}
public async Task<IEnumerable<DataSaubStatDto>> GetAsync(int idTelemetry, DateTimeOffset geDate, DateTimeOffset leDate, CancellationToken token)
{
var timeSpan = TimeSpan.FromHours(telemetryService.GetTimezone(idTelemetry).Hours);
var geDateUtc = geDate.ToUniversalTime();
var leDateUtc = leDate.ToUniversalTime();
var stats = await db.Set<DataSaubStat>()
.Where(s => s.IdTelemetry == idTelemetry)
.Where(s => s.DateStart >= geDateUtc)
.Where(s => s.DateEnd <= leDateUtc)
.ToArrayAsync(token);
var result = stats.Select(s => ConvertToDto(s, timeSpan));
return result;
}
public async Task<int> InsertRangeAsync(IEnumerable<DataSaubStatDto> dataSaubStats, CancellationToken token)
{
var entities = dataSaubStats.Select(data => ConvertToEntity(data));
db.Set<DataSaubStat>().AddRange(entities);
return await db.SaveChangesAsync(token);
}
private static DataSaubStatDto ConvertToDto(DataSaubStat entity, TimeSpan timeSpan)
{
var dto = entity.Adapt<DataSaubStatDto>();
dto.DateStart = dto.DateStart.ToOffset(timeSpan);
dto.DateEnd = dto.DateEnd.ToOffset(timeSpan);
return dto;
}
private static DataSaubStat ConvertToEntity(DataSaubStatDto dto)
{
var entity = dto.Adapt<DataSaubStat>();
entity.DateStart = dto.DateStart.ToUniversalTime();
entity.DateEnd = dto.DateEnd.ToUniversalTime();
return entity;
}
}
}

View File

@ -0,0 +1,200 @@
using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository;
public class DetectedOperationRepository : CrudRepositoryBase<DetectedOperationDto, DetectedOperation>,
IDetectedOperationRepository
{
private readonly ITelemetryService telemetryService;
public DetectedOperationRepository(IAsbCloudDbContext context,
ITelemetryService telemetryService)
: base(context)
{
this.telemetryService = telemetryService;
}
public async Task<int> Delete(int idUser, DetectedOperationByTelemetryRequest request, CancellationToken token)
{
var query = BuildQuery(request);
dbContext.Set<DetectedOperation>().RemoveRange(query);
return await dbContext.SaveChangesAsync(token);
}
public async Task<int> DeleteRange(int idUser, IEnumerable<int> ids, CancellationToken token)
{
var query = dbContext.Set<DetectedOperation>()
.Where(e => ids.Contains( e.Id));
dbContext.Set<DetectedOperation>()
.RemoveRange(query);
return await dbContext.SaveChangesAsync(token);
}
public async Task<IDictionary<int, DateTimeOffset>> GetLastDetectedDatesAsync(CancellationToken token) =>
await dbContext.Set<DetectedOperation>()
.GroupBy(o => o.IdTelemetry)
.Select(g => new
{
IdTelemetry = g.Key,
LastDate = g.Max(o => o.DateEnd)
})
.ToDictionaryAsync(x => x.IdTelemetry, x => x.LastDate, token);
public async Task<IEnumerable<DetectedOperationDto>> Get(DetectedOperationByTelemetryRequest request, CancellationToken token)
{
var query = BuildQuery(request)
.Include(o => o.OperationCategory);
var entities = await query.ToArrayAsync(token);
var offset = telemetryService.GetTimezone(request.IdTelemetry).Offset;
var dtos = entities.Select(o => Convert(o, offset));
return dtos;
}
public async Task<int> Insert(int? idUser, IEnumerable<DetectedOperationDto> dtos, CancellationToken token)
{
if(!dtos.Any())
return 0;
var entities = dtos.Select(Convert);
var dbset = dbContext.Set<DetectedOperation>();
foreach(var entity in entities)
{
entity.Id = default;
dbset.Add(entity);
}
return await dbContext.SaveChangesWithExceptionHandling(token);
}
public async Task<int> Update(int idUser, IEnumerable<DetectedOperationDto> dtos, CancellationToken token)
{
if (!dtos.Any())
return 0;
var ids = dtos
.Select(o => o.Id)
.Distinct()
.ToArray();
if (ids.Any(id => id == default))
throw new ArgumentInvalidException(nameof(dtos), "Все записи должны иметь Id");
if (ids.Length != dtos.Count())
throw new ArgumentInvalidException(nameof(dtos), "Все записи должны иметь уникальные Id");
var dbSet = dbContext.Set<DetectedOperation>();
var existingEntitiesCount = await dbSet
.Where(o => ids.Contains(o.Id))
.CountAsync(token);
if (ids.Length != existingEntitiesCount)
throw new ArgumentInvalidException(nameof(dtos), "Все записи должны существовать в БД");
var entities = dtos
.Select(Convert)
.ToArray();
var entries = new Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<DetectedOperation>[entities.Length];
for(var i = 0; i < entities.Length; i++)
entries[i] = dbSet.Update(entities[i]);
var result = await dbContext.SaveChangesWithExceptionHandling(token);
for (var i = 0; i < entries.Length; i++)
entries[i].State = EntityState.Detached;
return result;
}
public async Task<int> UpdateOrInsert(int idUser, IEnumerable<DetectedOperationDto> dtos, CancellationToken token)
{
var result = 0;
var itemsToInsert = dtos.Where(e => e.Id == 0);
if (itemsToInsert.Any())
result += await Insert(idUser, itemsToInsert, token);
var itemsToUpdate = dtos.Where(e => e.Id != 0);
if (itemsToUpdate.Any())
result += await Update(idUser, itemsToUpdate, token);
return result;
}
private IQueryable<DetectedOperation> BuildQuery(DetectedOperationByTelemetryRequest request)
{
var query = dbContext.Set<DetectedOperation>()
.Where(o => o.IdTelemetry == request.IdTelemetry);
if (request.IdsCategories.Any())
query = query.Where(o => request.IdsCategories.Contains(o.IdCategory));
if (request.GeDepthStart is not null)
query = query.Where(o => o.DepthStart >= request.GeDepthStart);
if (request.LeDepthEnd is not null)
query = query.Where(o => o.DepthEnd <= request.LeDepthEnd);
if (request.GeDateStart is not null)
{
var geDate = request.GeDateStart.Value.ToUniversalTime();
query = query.Where(o => o.DateStart >= geDate);
}
if (request.LeDateEnd is not null)
{
var leDate = request.LeDateEnd.Value.ToUniversalTime();
query = query.Where(o => o.DateEnd <= leDate);
}
if (request.SortFields?.Any() == true)
{
query = query.SortBy(request.SortFields);
}
else
query = query
.OrderBy(o => o.DateStart)
.ThenBy(o => o.DepthStart);
if (request.Skip.HasValue)
query = query.Skip((int)request.Skip);
if (request.Take.HasValue)
query = query.Take((int)request.Take);
return query;
}
protected virtual DetectedOperationDto Convert(DetectedOperation src, TimeSpan offset)
{
var dto = src.Adapt<DetectedOperationDto>();
dto.DateStart = src.DateStart.ToOffset(offset);
dto.DateEnd = src.DateEnd.ToOffset(offset);
return dto;
}
protected override DetectedOperation Convert(DetectedOperationDto src)
{
var entity = src.Adapt<DetectedOperation>();
entity.DateStart = src.DateStart.ToUniversalTime();
entity.DateEnd = src.DateEnd.ToUniversalTime();
return entity;
}
}

View File

@ -63,7 +63,7 @@ namespace AsbCloudInfrastructure.Repository
return dto;
}
public async Task<int> SaveDataAsync(int idTelemetry, DrillTestDto dto, CancellationToken token)
public async Task<int> SaveDataAsync(int idTelemetry, DrillTestBaseDto dto, CancellationToken token)
{
var entity = dto.Adapt<DrillTest>();
entity.IdTelemetry = idTelemetry;

View File

@ -1,4 +1,4 @@
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
@ -23,11 +23,12 @@ public class ProcessMapPlanBaseRepository<TDto, TEntity> : ChangeLogRepositoryAb
protected override IQueryable<TEntity> BuildQuery(ProcessMapPlanBaseRequestWithWell request)
{
var query = context
var query = db
.Set<TEntity>()
.Include(e => e.Author)
.Include(e => e.Editor)
.Include(e => e.Well)
.Include(e => e.WellSectionType)
.Where(e => e.IdWell == request.IdWell);
if (request.IdWellSectionType.HasValue)
@ -56,4 +57,19 @@ public class ProcessMapPlanBaseRepository<TDto, TEntity> : ChangeLogRepositoryAb
var offset = TimeSpan.FromHours(timezone.Hours);
return offset;
}
protected override TDto Convert(TEntity entity, TimeSpan offset)
{
var dto = base.Convert(entity, offset);
dto.Section = entity.WellSectionType.Caption;
return dto;
}
protected override TEntity Convert(TDto dto)
{
var entity = base.Convert(dto);
entity.Author = null;
entity.Editor = null;
return entity;
}
}

View File

@ -1,89 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudDb.Model.ProcessMaps;
using Microsoft.EntityFrameworkCore;
namespace AsbCloudInfrastructure.Repository;
public class ProcessMapPlanRepository<TDto, TEntity> : CrudWellRelatedRepositoryBase<TDto, TEntity>,
IProcessMapPlanRepository<TDto>
where TDto : ProcessMapPlanBaseDto
where TEntity : ProcessMapBase
{
private readonly IWellService wellService;
public ProcessMapPlanRepository(IAsbCloudDbContext context, IWellService wellService)
: base(context, dbSet =>
dbSet
.Include(p => p.WellSectionType)
.Include(p => p.Well))
{
this.wellService = wellService;
}
public async Task<IEnumerable<TDto>> GetAsync(IEnumerable<ProcessMapPlanRequest> requests, CancellationToken cancellationToken)
{
var query = BuildQuery(requests);
var entities = await query.ToArrayAsync(cancellationToken);
return entities.Select(Convert);
}
public Task<int> RemoveByWellAsync(int idWell)
{
var query = GetQuery().Where(x => x.IdWell == idWell);
dbSet.RemoveRange(query);
return dbContext.SaveChangesAsync(CancellationToken.None);
}
private IQueryable<TEntity> BuildQuery(IEnumerable<ProcessMapPlanRequest> requests)
{
var queries = requests
.Select(request => BuildQuery(request))
.ToArray();
var query = queries.FirstOrDefault()
?? throw new ArgumentInvalidException(nameof(requests), "Пустые запросы недопустимы");
for ( var i = 1; i < queries.Length; i++)
query = query.Union(queries[i]);
query = query
.Distinct()
.OrderBy(e => e.DepthStart)
.ThenBy(e => e.Id)
.AsNoTracking();
return query;
}
private IQueryable<TEntity> BuildQuery(ProcessMapPlanRequest request)
{
var query = GetQuery();
query = query.Where(p => p.IdWell == request.IdWell);
if (request.IdWellSectionType is not null)
query = query.Where(p => p.IdWellSectionType == request.IdWellSectionType);
if (request.UpdateFrom is not null)
{
var timezone = wellService.GetTimezone(request.IdWell);
var updateFromUtc = request.UpdateFrom?.ToUtcDateTimeOffset(timezone.Hours);
query = query.Where(p => p.LastUpdate >= updateFromUtc);
}
return query;
}
}

View File

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Requests;
using Mapster;
namespace AsbCloudInfrastructure.Repository
@ -53,6 +54,21 @@ namespace AsbCloudInfrastructure.Repository
return entity?.Driller.Adapt<DrillerDto>();
}
public async Task<IEnumerable<ScheduleDto>> GetPageAsync(GetStatRequest request, CancellationToken token)
{
var idWell = request.IdsWells;
var idDriller = request.IdDriller;
var query = GetQuery().Where(s => request.IdsWells.Contains(s.IdWell));
if (idDriller is not null)
{
query.Where(s => s.IdDriller == idDriller);
}
var result = await query.ToArrayAsync(token);
return result.Select(Convert);
}
private IQueryable<Schedule> BuildQuery(int idWell, DateTime workTime)
{
var hoursOffset = wellService.GetTimezone(idWell).Hours;

View File

@ -11,69 +11,69 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository
namespace AsbCloudInfrastructure.Repository;
public class WellCompositeRepository : IWellCompositeRepository
{
private readonly IAsbCloudDbContext db;
private readonly IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> processMapPlanDrillingRepository;
public class WellCompositeRepository : IWellCompositeRepository
public WellCompositeRepository(
IAsbCloudDbContext db,
IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> processMapPlanDrillingRepository)
{
private readonly IAsbCloudDbContext db;
private readonly IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingRepository;
public WellCompositeRepository(IAsbCloudDbContext db, IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingRepository)
{
this.db = db;
this.processMapPlanWellDrillingRepository = processMapPlanWellDrillingRepository;
}
/// <inheritdoc/>
public async Task<IEnumerable<WellCompositeDto>> GetAsync(int idWell, CancellationToken token)
{
var entities = await db.WellComposites
.Where(c => c.IdWell == idWell)
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
return entities.Select(Convert);
}
/// <inheritdoc/>
public Task<int> SaveAsync(int idWell, IEnumerable<WellCompositeDto> wellComposites, CancellationToken token)
{
db.WellComposites.RemoveRange(db.WellComposites
.Where(c => c.IdWell == idWell));
var entities = wellComposites
.Select(w => Convert(idWell, w));
db.WellComposites.AddRange(entities);
return db.SaveChangesAsync(token);
}
/// <inheritdoc/>
public async Task<IEnumerable<ProcessMapPlanWellDrillingDto>> GetCompositeProcessMap(int idWell, CancellationToken token)
{
var dtos = await GetAsync(idWell, token);
var requests = dtos.Select(x => new ProcessMapPlanRequest {
IdWell = x.IdWellSrc,
IdWellSectionType = x.IdWellSectionType
});
var result = await processMapPlanWellDrillingRepository.GetAsync(requests, token);
return result;
}
private static WellComposite Convert(int idWell, WellCompositeDto dto)
{
var entity = dto.Adapt<WellComposite>();
entity.IdWell = idWell;
return entity;
}
private static WellCompositeDto Convert(WellComposite entity)
{
var dto = entity.Adapt<WellCompositeDto>();
return dto;
}
this.db = db;
this.processMapPlanDrillingRepository = processMapPlanDrillingRepository;
}
/// <inheritdoc/>
public async Task<IEnumerable<WellCompositeDto>> GetAsync(int idWell, CancellationToken token)
{
var entities = await db.WellComposites
.Where(c => c.IdWell == idWell)
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
return entities.Select(Convert);
}
/// <inheritdoc/>
public Task<int> SaveAsync(int idWell, IEnumerable<WellCompositeDto> wellComposites, CancellationToken token)
{
db.WellComposites.RemoveRange(db.WellComposites
.Where(c => c.IdWell == idWell));
var entities = wellComposites
.Select(w => Convert(idWell, w));
db.WellComposites.AddRange(entities);
return db.SaveChangesAsync(token);
}
/// <inheritdoc/>
public async Task<IEnumerable<ProcessMapPlanDrillingDto>> GetCompositeProcessMap(int idWell, CancellationToken token)
{
var dtos = await GetAsync(idWell, token);
var requests = dtos.Select(x => new ProcessMapPlanRequest {
IdWell = x.IdWellSrc,
IdWellSectionType = x.IdWellSectionType
});
//var result = await processMapPlanDrillingRepository.GetAsync(requests, token);
return Enumerable.Empty<ProcessMapPlanDrillingDto>();
}
private static WellComposite Convert(int idWell, WellCompositeDto dto)
{
var entity = dto.Adapt<WellComposite>();
entity.IdWell = idWell;
return entity;
}
private static WellCompositeDto Convert(WellComposite entity)
{
var dto = entity.Adapt<WellCompositeDto>();
return dto;
}
}

View File

@ -0,0 +1,44 @@
using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudInfrastructure.Repository;
public class WellOperationCategoryRepository : IWellOperationCategoryRepository
{
private readonly IAsbCloudDbContext db;
private readonly IMemoryCache memoryCache;
public WellOperationCategoryRepository(IAsbCloudDbContext db, IMemoryCache memoryCache)
{
this.db = db;
this.memoryCache = memoryCache;
}
public IEnumerable<WellOperationCategoryDto> Get(bool includeParents)
{
var categories = memoryCache
.GetOrCreateBasic(db.Set<WellOperationCategory>());
if (!includeParents)
{
var parentIds = categories
.Select(o => o.IdParent)
.Distinct();
categories = categories
.Where(o => !parentIds.Contains(o.Id));
}
var result = categories
.OrderBy(o => o.Name)
.Adapt<IEnumerable<WellOperationCategoryDto>>();
return result;
}
}

View File

@ -10,56 +10,33 @@ using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository;
/// <summary>
/// репозиторий операций по скважине
/// </summary>
public class WellOperationRepository : IWellOperationRepository
{
private const string KeyCacheSections = "OperationsBySectionSummarties";
private const int Gap = 90;
private readonly IAsbCloudDbContext db;
private readonly IMemoryCache memoryCache;
private readonly IWellService wellService;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
public WellOperationRepository(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService)
public WellOperationRepository(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService, IWellOperationCategoryRepository wellOperationCategoryRepository)
{
this.db = db;
this.memoryCache = memoryCache;
this.wellService = wellService;
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
}
/// <inheritdoc/>
public IEnumerable<WellOperationCategoryDto> GetCategories(bool includeParents)
{
var categories = memoryCache
.GetOrCreateBasic(db.Set<WellOperationCategory>());
if (!includeParents)
{
var parentIds = categories
.Select(o => o.IdParent)
.Distinct();
categories = categories
.Where(o => !parentIds.Contains(o.Id));
}
var result = categories
.OrderBy(o => o.Name)
.Adapt<IEnumerable<WellOperationCategoryDto>>();
return result;
}
/// <inheritdoc/>
public IEnumerable<WellSectionTypeDto> GetSectionTypes() =>
memoryCache
.GetOrCreateBasic(db.Set<WellSectionType>())
@ -228,6 +205,17 @@ public class WellOperationRepository : IWellOperationRepository
return dtos.Select(Convert);
}
public async Task<IEnumerable<WellOperationDataDto>> GetAsync(
WellsOperationRequest request,
CancellationToken token)
{
var query = BuildQuery(request)
.AsNoTracking();
var dtos = await query.ToArrayAsync(token);
return dtos;
}
/// <inheritdoc/>
public async Task<PaginationContainer<WellOperationDto>> GetPageAsync(
WellOperationRequest request,
@ -287,7 +275,7 @@ public class WellOperationRepository : IWellOperationRepository
DurationDepth = o.DepthEnd - o.DepthStart
})
.ToListAsync(token);
var parentRelationDictionary = GetCategories(true)
var parentRelationDictionary = wellOperationCategoryRepository.Get(true)
.ToDictionary(c => c.Id, c => new
{
c.Name,
@ -333,62 +321,6 @@ public class WellOperationRepository : IWellOperationRepository
return dtos;
}
public async Task<IEnumerable<ValidationResult>> ValidateWithDbAsync(IEnumerable<WellOperationDto> wellOperationDtos, CancellationToken token)
{
var firstOperation = wellOperationDtos
.FirstOrDefault();
if (firstOperation is null)
return Enumerable.Empty<ValidationResult>();
var request = new WellOperationRequest()
{
IdWell = firstOperation.IdWell,
OperationType = firstOperation.IdType,
};
var dtos = await BuildQuery(request)
.AsNoTracking()
.ToArrayAsync(token);
var dtosWithRemoteDateTime = dtos.Select(Convert);
var wellOperationsUnion = dtosWithRemoteDateTime.Union(dtos).OrderBy(o => o.DateStart);
var results = Validate(wellOperationsUnion);
return results;
}
public IEnumerable<ValidationResult> Validate(IEnumerable<WellOperationDto> wellOperationDtos)
{
var enumerator = wellOperationDtos.OrderBy(o => o.DateStart)
.GetEnumerator();
if (!enumerator.MoveNext())
yield break;
var timezone = wellService.GetTimezone(wellOperationDtos.First().IdWell);
var timezoneOffset = timezone.Hours;
var previous = enumerator.Current;
while(enumerator.MoveNext())
{
var current = enumerator.Current;
var previousDateStart = previous.DateStart.DateTime.ToUtcDateTimeOffset(timezoneOffset);
var currentDateStart = current.DateStart.DateTime.ToUtcDateTimeOffset(timezoneOffset);
if (previousDateStart.AddDays(Gap) < currentDateStart)
{
yield return new ValidationResult(
"Разница дат между операциями не должна превышать 90 дней",
new[] { nameof(wellOperationDtos) });
}
previous = current;
}
}
/// <inheritdoc/>
public async Task<int> InsertRangeAsync(
IEnumerable<WellOperationDto> wellOperationDtos,
@ -464,7 +396,6 @@ public class WellOperationRepository : IWellOperationRepository
.Include(s => s.OperationCategory)
.Where(o => o.IdWell == request.IdWell);
if (request.OperationType.HasValue)
query = query.Where(e => e.IdType == request.OperationType.Value);
@ -499,6 +430,7 @@ public class WellOperationRepository : IWellOperationRepository
.Where(subOp => subOp.IdType == 1)
.Where(subOp => WellOperationCategory.NonProductiveTimeSubIds.Contains(subOp.IdCategory));
// TODO: Вынести query.Select из метода BuildQuery
var dtos = query.Select(o => new WellOperationDto
{
Id = o.Id,
@ -551,6 +483,50 @@ public class WellOperationRepository : IWellOperationRepository
return dtos.AsNoTracking();
}
/// <summary>
/// Получение данных по запросу
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
private IQueryable<WellOperationDataDto> BuildQuery(WellsOperationRequest request)
{
var query = db.WellOperations
.Where(o => request.IdsWell.Contains(o.IdWell))
.Where(o => request.OperationType == o.IdType);
if (request.SectionTypeIds?.Any() == true)
query = query.Where(o => request.SectionTypeIds.Contains(o.IdWellSectionType));
if (request.OperationCategoryIds?.Any() == true)
query = query.Where(o => request.OperationCategoryIds.Contains(o.IdCategory));
// TODO: Вынести query.Select из метода BuildQuery
var dtos = query.Select(o => new WellOperationDataDto
{
DepthStart = o.DepthStart,
DurationHours = o.DurationHours,
IdCategory = o.IdCategory,
IdWell = o.IdWell,
IdWellSectionType = o.IdWellSectionType,
OperationCategoryName = o.OperationCategory.Name,
WellSectionTypeCaption = o.WellSectionType.Caption,
});
if (request.SortFields?.Any() == true)
{
dtos = dtos.SortBy(request.SortFields);
}
if (request.Skip.HasValue)
dtos = dtos.Skip(request.Skip.Value);
if (request.Take.HasValue)
dtos = dtos.Take(request.Take.Value);
return dtos.AsNoTracking();
}
private WellOperationDto Convert(WellOperationDto dto)
{
var timezone = wellService.GetTimezone(dto.IdWell);
@ -563,4 +539,161 @@ public class WellOperationRepository : IWellOperationRepository
return dtoWithRemoteDateTime;
}
public async Task<int> RemoveDuplicates(Action<string, double?> onProgressCallback, CancellationToken token)
{
IQueryable<WellOperation> dbset = db.Set<WellOperation>();
var query = dbset
.GroupBy(o => new { o.IdWell, o.IdType })
.Select(g => new { g.Key.IdWell, g.Key.IdType });
var groups = await query
.ToArrayAsync(token);
var count = groups.Count();
var i = 0;
var totalRemoved = 0;
var total = 0;
foreach (var group in groups)
{
var result = await RemoveDuplicatesInGroup(group.IdWell, group.IdType, token);
totalRemoved += result.removed;
total += result.total;
var percent = i++ / count;
var message = $"RemoveDuplicates [{i} of {count}] wellId: {group.IdWell}, opType: {group.IdType}, affected: {result.removed} of {result.total}";
onProgressCallback?.Invoke(message, percent);
Trace.TraceInformation(message);
}
var messageDone = $"RemoveDuplicates done [{i} of {count}] totalAffected: {totalRemoved} of {total}";
Trace.TraceInformation(messageDone);
onProgressCallback?.Invoke(messageDone, 1);
return totalRemoved;
}
private async Task<(int removed, int total)> RemoveDuplicatesInGroup(int idWell, int idType, CancellationToken token)
{
var dbset = db.Set<WellOperation>();
var entities = await dbset
.Where(o => o.IdWell == idWell && o.IdType == idType)
.OrderBy(o => o.DateStart)
.ToListAsync(token);
using var entitiesEnumerator = entities.GetEnumerator();
if (!entitiesEnumerator.MoveNext())
return (0, 0);
var preEntity = entitiesEnumerator.Current;
while (entitiesEnumerator.MoveNext())
{
var entity = entitiesEnumerator.Current;
if (preEntity.IsSame(entity))
dbset.Remove(entity);
else
preEntity = entity;
}
var removed = await db.SaveChangesAsync(token);
return (removed, entities.Count);
}
public async Task<int> TrimOverlapping(DateTimeOffset? geDate, DateTimeOffset leDate, Action<string, double?> onProgressCallback, CancellationToken token)
{
var leDateUtc = leDate.ToUniversalTime();
IQueryable<WellOperation> query = db.Set<WellOperation>();
if (geDate.HasValue)
{
var geDateUtc = geDate.Value.ToUniversalTime();
query = query.Where(e => e.DateStart >= geDateUtc);
}
var groups = await query
.GroupBy(o => new { o.IdWell, o.IdType })
.Select(g => new{
MaxDate = g.Max(o => o.DateStart),
g.Key.IdWell,
g.Key.IdType,
})
.Where(g => g.MaxDate <= leDateUtc)
.ToArrayAsync(token);
var count = groups.Count();
var i = 0;
(int takeover, int trimmed,int total) totalResult = (0, 0, 0);
foreach (var group in groups)
{
var result = await TrimOverlapping(group.IdWell, group.IdType, token);
totalResult.takeover += result.takeover;
totalResult.trimmed += result.trimmed;
totalResult.total += result.total;
var percent = i++ / count;
var message = $"TrimOverlapping [{i} of {count}] wellId: {group.IdWell}, opType: {group.IdType}, takeover:{result.takeover}, trimmed:{result.trimmed}, of {result.total}";
onProgressCallback?.Invoke(message, percent);
Trace.TraceInformation(message);
}
var messageDone = $"TrimOverlapping done [{i} of {count}] total takeover:{totalResult.takeover}, total trimmed:{totalResult.trimmed} of {totalResult.total}";
Trace.TraceInformation(messageDone);
onProgressCallback?.Invoke(messageDone, 1);
return totalResult.takeover + totalResult.trimmed;
}
private async Task<(int takeover, int trimmed, int total)> TrimOverlapping(int idWell, int idType, CancellationToken token)
{
var dbset = db.Set<WellOperation>();
var query = dbset
.Where(o => o.IdWell == idWell)
.Where(o => o.IdType == idType)
.OrderBy(o => o.DateStart)
.ThenBy(o => o.DepthStart);
var entities = await query
.ToListAsync(token);
using var entitiesEnumerator = entities.GetEnumerator();
if (!entitiesEnumerator.MoveNext())
return (0, 0, 0);
int takeover = 0;
int trimmed = 0;
var preEntity = entitiesEnumerator.Current;
while (entitiesEnumerator.MoveNext())
{
var entity = entitiesEnumerator.Current;
var preDepth = preEntity.DepthEnd;
if (preEntity.DepthEnd >= entity.DepthEnd)
{
dbset.Remove(entity);
takeover++;
continue;
}
if (preEntity.DepthEnd > entity.DepthStart)
{
entity.DepthStart = preEntity.DepthEnd;
trimmed++;
}
var preDate = preEntity.DateStart.AddHours(preEntity.DurationHours);
if (preDate >= entity.DateStart.AddHours(entity.DurationHours))
{
dbset.Remove(entity);
takeover++;
continue;
}
if (preDate > entity.DateStart)
{
var entityDateEnd = entity.DateStart.AddHours(entity.DurationHours);
entity.DateStart = preDate;
entity.DurationHours = (entityDateEnd - entity.DateStart).TotalHours;
trimmed++;
}
preEntity = entity;
}
var affected = await db.SaveChangesAsync(token);
return (takeover, trimmed, entities.Count);
}
}

Some files were not shown because too many files have changed in this diff Show More