This commit is contained in:
ngfrolov 2022-06-01 17:52:26 +05:00
parent b89ea13c78
commit 1e7f5fe654
22 changed files with 272 additions and 462 deletions

View File

@ -3,8 +3,10 @@ using System.Collections.Generic;
namespace AsbCloudApp.Comparators namespace AsbCloudApp.Comparators
{ {
/// <inheritdoc/>
public class TelemetryUserDtoComparer : IEqualityComparer<TelemetryUserDto> public class TelemetryUserDtoComparer : IEqualityComparer<TelemetryUserDto>
{ {
/// <inheritdoc/>
public bool Equals(TelemetryUserDto prevUser, TelemetryUserDto nextUser) public bool Equals(TelemetryUserDto prevUser, TelemetryUserDto nextUser)
{ {
if (prevUser is null || nextUser is null) if (prevUser is null || nextUser is null)
@ -15,6 +17,7 @@ namespace AsbCloudApp.Comparators
return false; return false;
} }
/// <inheritdoc/>
public int GetHashCode(TelemetryUserDto user) => user.Id.GetHashCode(); public int GetHashCode(TelemetryUserDto user) => user.Id.GetHashCode();
} }
} }

View File

@ -2,15 +2,43 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
#nullable enable
/// <summary>
/// DTO кустов
/// </summary>
public class ClusterDto : IMapPoint, IId public class ClusterDto : IMapPoint, IId
{ {
/// <inheritdoc/>
public int Id { get; set; } public int Id { get; set; }
public string Caption { get; set; }
/// <summary>
/// Название
/// </summary>
public string Caption { get; set; } = null!;
/// <inheritdoc/>
public double? Latitude { get; set; } public double? Latitude { get; set; }
/// <inheritdoc/>
public double? Longitude { get; set; } public double? Longitude { get; set; }
public SimpleTimezoneDto Timezone { get; set; }
/// <inheritdoc/>
public SimpleTimezoneDto Timezone { get; set; } = null!;
/// <summary>
/// ИД месторождения, необязательный
/// </summary>
public int? IdDeposit { get; set; } public int? IdDeposit { get; set; }
public DepositBaseDto Deposit { get; set; }
public IEnumerable<WellDto> Wells { get; set; } /// <summary>
/// DTO месторождения
/// </summary>
public DepositBaseDto? Deposit { get; set; }
/// <summary>
/// Список скважин куста
/// </summary>
public IEnumerable<WellDto> Wells { get; set; } = null!;
} }
#nullable disable
} }

View File

@ -1,8 +1,18 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
/// <summary>
/// Статистика механической скорости проходки (МСП) по кусту
/// </summary>
public class ClusterRopStatDto public class ClusterRopStatDto
{ {
/// <summary>
/// Макс. механическая скорость проходки по кусту
/// </summary>
public double RopMax { get; set; } public double RopMax { get; set; }
/// <summary>
/// Средняя механическая скорость проходки по кусту
/// </summary>
public double RopAverage { get; set; } public double RopAverage { get; set; }
} }
} }

View File

@ -1,11 +1,26 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
/// <summary>
/// DTO компании
/// </summary>
public class CompanyDto : IId public class CompanyDto : IId
{ {
/// <inheritdoc/>
public int Id { get; set; } public int Id { get; set; }
/// <summary>
/// Название
/// </summary>
public string Caption { get; set; } public string Caption { get; set; }
/// <summary>
/// ИД типа компании
/// </summary>
public int IdCompanyType { get; set; } public int IdCompanyType { get; set; }
/// <summary>
/// Название типа компании
/// </summary>
public string CompanyTypeCaption { get; set; } public string CompanyTypeCaption { get; set; }
} }
} }

View File

@ -1,8 +1,16 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
/// <summary>
/// DTO тип компании
/// </summary>
public class CompanyTypeDto : IId public class CompanyTypeDto : IId
{ {
/// <inheritdoc/>
public int Id { get; set; } public int Id { get; set; }
/// <summary>
/// Название типа компании
/// </summary>
public string Caption { get; set; } public string Caption { get; set; }
} }

View File

@ -2,9 +2,19 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
/// <summary>
/// Диапазон дат
/// </summary>
public class DatesRangeDto public class DatesRangeDto
{ {
/// <summary>
/// Дата начала диапазона
/// </summary>
public DateTime From { get; set; } public DateTime From { get; set; }
/// <summary>
/// Дата окончания диапазона
/// </summary>
public DateTime To { get; set; } public DateTime To { get; set; }
} }
} }

View File

@ -2,17 +2,37 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
/// <summary>
/// DTO Месторождения
/// </summary>
public class DepositBaseDto : IMapPoint, IId public class DepositBaseDto : IMapPoint, IId
{ {
/// <inheritdoc/>
public int Id { get; set; } public int Id { get; set; }
/// <summary>
/// Название
/// </summary>
public string Caption { get; set; } public string Caption { get; set; }
/// <inheritdoc/>
public double? Latitude { get; set; } public double? Latitude { get; set; }
/// <inheritdoc/>
public double? Longitude { get; set; } public double? Longitude { get; set; }
/// <inheritdoc/>
public SimpleTimezoneDto Timezone { get; set; } public SimpleTimezoneDto Timezone { get; set; }
} }
/// <summary>
/// DTO Месторождения с кустами
/// </summary>
public class DepositDto : DepositBaseDto public class DepositDto : DepositBaseDto
{ {
/// <summary>
/// Кусты месторождения
/// </summary>
public IEnumerable<ClusterDto> Clusters { get; set; } public IEnumerable<ClusterDto> Clusters { get; set; }
} }
} }

View File

@ -7,6 +7,9 @@ namespace AsbCloudApp.Data
/// </summary> /// </summary>
public class DrillFlowChartDto : IId public class DrillFlowChartDto : IId
{ {
/// <summary>
/// <inheritdoc/>
/// </summary>
public int Id { get; set; } public int Id { get; set; }
/// <summary> /// <summary>

View File

@ -2,9 +2,19 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
/// <summary>
/// Часть программы бурения
/// </summary>
public class DrillingProgramPartDto public class DrillingProgramPartDto
{ {
/// <summary>
/// Название
/// </summary>
public string Name { get; set; } public string Name { get; set; }
/// <summary>
/// ИД категории файла
/// </summary>
public int IdFileCategory { get; set; } public int IdFileCategory { get; set; }
/// <summary> /// <summary>
@ -13,10 +23,30 @@ namespace AsbCloudApp.Data
/// 2 - completely approved /// 2 - completely approved
/// </summary> /// </summary>
public int IdState { get; set; } public int IdState { get; set; }
/// <summary>
/// Публикаторы. Могут загружать файл этой категории
/// </summary>
public IEnumerable<UserDto> Publishers { get; set; } public IEnumerable<UserDto> Publishers { get; set; }
/// <summary>
/// Согласованты. Могут согласовывать загруженные файлы этой категории
/// </summary>
public IEnumerable<UserDto> Approvers { get; set; } public IEnumerable<UserDto> Approvers { get; set; }
/// <summary>
/// Разрешение для текущего пользователя согласовывать документ
/// </summary>
public bool PermissionToApprove { get; set; } public bool PermissionToApprove { get; set; }
/// <summary>
/// Разрешение для текущего пользователя загружать документ
/// </summary>
public bool PermissionToUpload { get; set; } public bool PermissionToUpload { get; set; }
/// <summary>
/// Ссылка на документ.
/// </summary>
public FileInfoDto File { get; set; } public FileInfoDto File { get; set; }
} }
} }

View File

@ -1,7 +1,13 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
/// <summary>
/// Интерфейс данных с Id
/// </summary>
public interface IId public interface IId
{ {
/// <summary>
/// Идентификатор БД
/// </summary>
public int Id { get; set; } public int Id { get; set; }
} }
} }

View File

@ -1,9 +1,23 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
/// <summary>
/// точка на карте
/// </summary>
public interface IMapPoint public interface IMapPoint
{ {
/// <summary>
/// Широта
/// </summary>
double? Latitude { get; set; } double? Latitude { get; set; }
/// <summary>
/// Широта
/// </summary>
double? Longitude { get; set; } double? Longitude { get; set; }
/// <summary>
/// Часовой пояс
/// </summary>
SimpleTimezoneDto Timezone { get; set; } SimpleTimezoneDto Timezone { get; set; }
} }
} }

View File

@ -2,10 +2,19 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
/// <summary>
/// Интерфейс записи данных телеметрии
/// </summary>
public interface ITelemetryData public interface ITelemetryData
{ {
/// <summary>
/// ИД телеметрии
/// </summary>
int IdTelemetry { get; set; } int IdTelemetry { get; set; }
/// <summary>
/// Отметка времени для этой записи
/// </summary>
DateTime DateTime { get; set; } DateTime DateTime { get; set; }
} }
} }

View File

@ -2,16 +2,38 @@
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
/// <summary>
/// DTO телеметрии панели
/// </summary>
public class TelemetryBaseDto : IId public class TelemetryBaseDto : IId
{ {
/// <inheritdoc/>
public int Id { get; set; } public int Id { get; set; }
/// <summary>
/// уникальный идентификатор телеметрии по которому панель оператора присылает данные
/// </summary>
public string RemoteUid { get; set; } public string RemoteUid { get; set; }
/// <summary>
/// информация о бурении, панели оператора и контроллерах
/// </summary>
public TelemetryInfoDto Info { get; set; } public TelemetryInfoDto Info { get; set; }
} }
/// <summary>
/// DTO телеметрии панели с скважиной
/// </summary>
public class TelemetryDto : TelemetryBaseDto public class TelemetryDto : TelemetryBaseDto
{ {
/// <summary>
/// ИД скважины
/// </summary>
public int? IdWell { get; set; } public int? IdWell { get; set; }
/// <summary>
/// DTO скважины
/// </summary>
public WellInfoDto Well { get; set; } public WellInfoDto Well { get; set; }
} }
} }

View File

@ -14,7 +14,7 @@ namespace AsbCloudApp.Data.WITS
/// LongMnemonic = "DEPTBITM", /// LongMnemonic = "DEPTBITM",
/// ShortMnemonic = "DBTM", /// ShortMnemonic = "DBTM",
/// Description = "Depth Bit (meas)", /// Description = "Depth Bit (meas)",
/// Description2 = "Code indicating what activity is currently being performed on the rig. IT IS ESSENTIAL that this information be as accurate and current as possible. Acceptible codes are shownhere", /// Description2 = "Code indicating what activity is currently being performed on the rig. IT IS ESSENTIAL that this information be as accurate and current as possible. Acceptable codes are shown here",
/// FPSUnits = "F", /// FPSUnits = "F",
/// MetricUnits = "M", /// MetricUnits = "M",
/// Length = 4, /// Length = 4,
@ -103,7 +103,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 14, /// ItemId = 14,
/// LongMnemonic = "HKLA", /// LongMnemonic = "HKLA",
/// ShortMnemonic = "HKLA", /// ShortMnemonic = "HKLA",
/// Description = "Hookload (avg)", /// Description = "Hook-load (avg)",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "KLB", /// FPSUnits = "KLB",
/// MetricUnits = "KDN", /// MetricUnits = "KDN",
@ -118,7 +118,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 15, /// ItemId = 15,
/// LongMnemonic = "HKLX", /// LongMnemonic = "HKLX",
/// ShortMnemonic = "HKLX", /// ShortMnemonic = "HKLX",
/// Description = "Hookload (max)", /// Description = "Hook-load (max)",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "KLB", /// FPSUnits = "KLB",
/// MetricUnits = "KDN", /// MetricUnits = "KDN",
@ -508,7 +508,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 41, /// ItemId = 41,
/// LongMnemonic = "SPARE1", /// LongMnemonic = "SPARE1",
/// ShortMnemonic = "SPR1", /// ShortMnemonic = "SPR1",
/// Description = "< SPARE 1>", /// Description = "SPARE 1",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -523,7 +523,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 42, /// ItemId = 42,
/// LongMnemonic = "SPARE2", /// LongMnemonic = "SPARE2",
/// ShortMnemonic = "SPR2", /// ShortMnemonic = "SPR2",
/// Description = "< SPARE 2>", /// Description = "SPARE 2",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -538,7 +538,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 43, /// ItemId = 43,
/// LongMnemonic = "SPARE3", /// LongMnemonic = "SPARE3",
/// ShortMnemonic = "SPR3", /// ShortMnemonic = "SPR3",
/// Description = "< SPARE 3>", /// Description = "SPARE 3",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -553,7 +553,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 44, /// ItemId = 44,
/// LongMnemonic = "SPARE4", /// LongMnemonic = "SPARE4",
/// ShortMnemonic = "SPR4", /// ShortMnemonic = "SPR4",
/// Description = "< SPARE 4>", /// Description = "SPARE 4",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -568,7 +568,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 45, /// ItemId = 45,
/// LongMnemonic = "SPARE5", /// LongMnemonic = "SPARE5",
/// ShortMnemonic = "SPR5", /// ShortMnemonic = "SPR5",
/// Description = "< SPARE 5>", /// Description = "SPARE 5",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",

View File

@ -224,7 +224,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 22, /// ItemId = 22,
/// LongMnemonic = "SPARE1", /// LongMnemonic = "SPARE1",
/// ShortMnemonic = "SPR1", /// ShortMnemonic = "SPR1",
/// Description = "< SPARE 1>", /// Description = "SPARE 1",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -239,7 +239,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 23, /// ItemId = 23,
/// LongMnemonic = "SPARE2", /// LongMnemonic = "SPARE2",
/// ShortMnemonic = "SPR2", /// ShortMnemonic = "SPR2",
/// Description = "< SPARE 2>", /// Description = "SPARE 2",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -254,7 +254,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 24, /// ItemId = 24,
/// LongMnemonic = "SPARE3", /// LongMnemonic = "SPARE3",
/// ShortMnemonic = "SPR3", /// ShortMnemonic = "SPR3",
/// Description = "< SPARE 3>", /// Description = "SPARE 3",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -269,7 +269,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 25, /// ItemId = 25,
/// LongMnemonic = "SPARE4", /// LongMnemonic = "SPARE4",
/// ShortMnemonic = "SPR4", /// ShortMnemonic = "SPR4",
/// Description = "< SPARE 4>", /// Description = "SPARE 4",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -284,7 +284,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 26, /// ItemId = 26,
/// LongMnemonic = "SPARE5", /// LongMnemonic = "SPARE5",
/// ShortMnemonic = "SPR5", /// ShortMnemonic = "SPR5",
/// Description = "< SPARE 5>", /// Description = "SPARE 5",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "---", /// MetricUnits = "---",

View File

@ -599,7 +599,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 47, /// ItemId = 47,
/// LongMnemonic = "SPARE1", /// LongMnemonic = "SPARE1",
/// ShortMnemonic = "SPR1", /// ShortMnemonic = "SPR1",
/// Description = "< SPARE 1>", /// Description = "SPARE 1",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -614,7 +614,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 48, /// ItemId = 48,
/// LongMnemonic = "SPARE2", /// LongMnemonic = "SPARE2",
/// ShortMnemonic = "SPR2", /// ShortMnemonic = "SPR2",
/// Description = "< SPARE 2>", /// Description = "SPARE 2",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -629,7 +629,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 49, /// ItemId = 49,
/// LongMnemonic = "SPARE3", /// LongMnemonic = "SPARE3",
/// ShortMnemonic = "SPR3", /// ShortMnemonic = "SPR3",
/// Description = "< SPARE 3>", /// Description = "SPARE 3",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -644,7 +644,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 50, /// ItemId = 50,
/// LongMnemonic = "SPARE4", /// LongMnemonic = "SPARE4",
/// ShortMnemonic = "SPR4", /// ShortMnemonic = "SPR4",
/// Description = "< SPARE 4>", /// Description = "SPARE 4",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -659,7 +659,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 51, /// ItemId = 51,
/// LongMnemonic = "SPARE5", /// LongMnemonic = "SPARE5",
/// ShortMnemonic = "SPR5", /// ShortMnemonic = "SPR5",
/// Description = "< SPARE 5>", /// Description = "SPARE 5",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "---", /// MetricUnits = "---",
@ -674,7 +674,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 52, /// ItemId = 52,
/// LongMnemonic = "SPARE6", /// LongMnemonic = "SPARE6",
/// ShortMnemonic = "SPR6", /// ShortMnemonic = "SPR6",
/// Description = "< SPARE 6>", /// Description = "SPARE 6",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -689,7 +689,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 53, /// ItemId = 53,
/// LongMnemonic = "SPARE7", /// LongMnemonic = "SPARE7",
/// ShortMnemonic = "SPR7", /// ShortMnemonic = "SPR7",
/// Description = "< SPARE 7>", /// Description = "SPARE 7",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -704,7 +704,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 54, /// ItemId = 54,
/// LongMnemonic = "SPARE8", /// LongMnemonic = "SPARE8",
/// ShortMnemonic = "SPR8", /// ShortMnemonic = "SPR8",
/// Description = "< SPARE 8>", /// Description = "SPARE 8",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",
@ -719,7 +719,7 @@ namespace AsbCloudApp.Data.WITS
/// ItemId = 55, /// ItemId = 55,
/// LongMnemonic = "SPARE9", /// LongMnemonic = "SPARE9",
/// ShortMnemonic = "SPR9", /// ShortMnemonic = "SPR9",
/// Description = "< SPARE 9>", /// Description = "SPARE 9",
/// Description2 = "", /// Description2 = "",
/// FPSUnits = "----", /// FPSUnits = "----",
/// MetricUnits = "----", /// MetricUnits = "----",

View File

@ -8,24 +8,16 @@ namespace AsbCloudApp.Data
/// </summary> /// </summary>
public class WellDto : WellInfoDto, IMapPoint, IId public class WellDto : WellInfoDto, IMapPoint, IId
{ {
/// <summary> /// <inheritdoc/>
/// ID в БД
/// </summary>
public int Id { get; set; } public int Id { get; set; }
/// <summary> /// <inheritdoc/>
/// Широта
/// </summary>
public double? Latitude { get; set; } public double? Latitude { get; set; }
/// <summary> /// <inheritdoc/>
/// долгота
/// </summary>
public double? Longitude { get; set; } public double? Longitude { get; set; }
/// <summary> /// <inheritdoc/>
/// Упрощенная временная зона
/// </summary>
public SimpleTimezoneDto Timezone { get; set; } public SimpleTimezoneDto Timezone { get; set; }
/// <summary> /// <summary>

View File

@ -1,19 +1,71 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AsbCloudApp.Services namespace AsbCloudApp.Services
{ {
#nullable enable
/// <summary>
/// Сервис получения, добавления, изменения, удаления данных
/// </summary>
/// <typeparam name="Tdto"></typeparam>
public interface ICrudService<Tdto> public interface ICrudService<Tdto>
where Tdto : Data.IId where Tdto : Data.IId
{ {
/// <summary>
/// Включение связных данных
/// </summary>
ISet<string> Includes { get; } ISet<string> Includes { get; }
/// <summary>
/// Добавление новой записи
/// </summary>
/// <param name="newItem"></param>
/// <param name="token"></param>
/// <returns>Id новой записи</returns>
Task<int> InsertAsync(Tdto newItem, CancellationToken token = default); Task<int> InsertAsync(Tdto newItem, CancellationToken token = default);
/// <summary>
/// Добавление нескольких записей
/// </summary>
/// <param name="newItems"></param>
/// <param name="token"></param>
/// <returns>количество добавленных</returns>
Task<int> InsertRangeAsync(IEnumerable<Tdto> newItems, CancellationToken token = default); Task<int> InsertRangeAsync(IEnumerable<Tdto> newItems, CancellationToken token = default);
/// <summary>
/// Получение всех записей
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
[Obsolete("Небезопасный метод, может выполняться бесконечно долго")]
Task<IEnumerable<Tdto>> GetAllAsync(CancellationToken token = default); Task<IEnumerable<Tdto>> GetAllAsync(CancellationToken token = default);
Task<Tdto> GetAsync(int id, CancellationToken token = default);
/// <summary>
/// Получить запись по id
/// </summary>
/// <param name="id"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<Tdto?> GetAsync(int id, CancellationToken token = default);
/// <summary>
/// Отредактировать запись
/// </summary>
/// <param name="id"></param>
/// <param name="item"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> UpdateAsync(int id, Tdto item, CancellationToken token = default); Task<int> UpdateAsync(int id, Tdto item, CancellationToken token = default);
/// <summary>
/// Удалить запись
/// </summary>
/// <param name="id"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> DeleteAsync(int id, CancellationToken token = default); Task<int> DeleteAsync(int id, CancellationToken token = default);
Task<int> DeleteAsync(IEnumerable<int> ids, CancellationToken token = default);
} }
#nullable disable
} }

View File

@ -1,411 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.Cache
{
#nullable enable
/// <summary>
/// Кеширование запросов EF.
/// </summary>
public static class EfCacheL2
{
/// <summary>
/// Кол-во обращений к БД.
/// </summary>
public static int CountOfRequestsToDB = 0;
private static readonly Dictionary<string, CacheItem> caches = new(16);
private static readonly TimeSpan semaphoreTimeout = TimeSpan.FromSeconds(25);
private static readonly SemaphoreSlim semaphore = new(1);
private static readonly TimeSpan minCacheTime = TimeSpan.FromSeconds(2);
private class CacheItem
{
internal IEnumerable? Data;
internal DateTime DateObsolete;
internal DateTime DateObsoleteTotal;
internal readonly SemaphoreSlim semaphore = new(1);
}
private static CacheItem GetOrAddCache(string tag, Func<IEnumerable> valueFactory, TimeSpan obsolete)
{
CacheItem cache;
while (!caches.ContainsKey(tag))
{
if (semaphore.Wait(0))
{
try {
cache = new CacheItem();
var dateObsolete = DateTime.Now + obsolete;
var dateQueryStart = DateTime.Now;
var data = valueFactory();
var queryTime = DateTime.Now - dateQueryStart;
if (dateObsolete - DateTime.Now < minCacheTime)
dateObsolete = DateTime.Now + minCacheTime;
cache.Data = data;
cache.DateObsolete = dateObsolete;
cache.DateObsoleteTotal = dateObsolete + queryTime + minCacheTime;
caches.Add(tag, cache);
}
catch
{
throw;
}
finally
{
semaphore.Release();
}
break;
}
else
{
if (semaphore.Wait(semaphoreTimeout))
{
semaphore.Release();
}
else
{
semaphore.Release();
throw new TimeoutException("EfCacheL2.GetOrAddCache. Can't wait too long while getting cache");
}
}
}
cache = caches[tag];
if (cache.DateObsolete < DateTime.Now)
{
if (cache.semaphore.Wait(0))
{
try
{
var dateObsolete = DateTime.Now + obsolete;
var dateQueryStart = DateTime.Now;
var data = valueFactory();
var queryTime = DateTime.Now - dateQueryStart;
if (dateObsolete - DateTime.Now < minCacheTime)
dateObsolete = DateTime.Now + minCacheTime;
cache.Data = data;
cache.DateObsolete = dateObsolete;
cache.DateObsoleteTotal = dateObsolete + queryTime + minCacheTime;
}
catch
{
throw;
}
finally
{
cache.semaphore.Release();
}
}
else if(cache.DateObsoleteTotal < DateTime.Now)
{
if (cache.semaphore.Wait(semaphoreTimeout))
{
cache.semaphore.Release();
}
else
{
cache.semaphore.Release();
throw new TimeoutException("EfCacheL2.GetOrAddCache. Can't wait too long while getting cache");
}
}
}
return cache;
}
private static async Task<CacheItem> GetOrAddCacheAsync(string tag, Func<CancellationToken, Task<IEnumerable>> valueFactoryAsync, TimeSpan obsolete, CancellationToken token)
{
CacheItem cache;
while (!caches.ContainsKey(tag))
{
if (semaphore.Wait(0))
{
try
{
cache = new CacheItem();
var dateObsolete = DateTime.Now + obsolete;
var dateQueryStart = DateTime.Now;
var data = await valueFactoryAsync(token);
var queryTime = DateTime.Now - dateQueryStart;
if (dateObsolete - DateTime.Now < minCacheTime)
dateObsolete = DateTime.Now + minCacheTime;
cache.Data = data;
cache.DateObsolete = dateObsolete;
cache.DateObsoleteTotal = dateObsolete + queryTime + minCacheTime;
caches.Add(tag, cache);
}
catch
{
throw;
}
finally
{
semaphore.Release();
}
break;
}
else
{
if (await semaphore.WaitAsync(semaphoreTimeout, token))
{
semaphore.Release();
}
else
{
semaphore.Release();
throw new TimeoutException("EfCacheL2.GetOrAddCache. Can't wait too long while getting cache");
}
}
}
cache = caches[tag];
if (cache.DateObsolete < DateTime.Now)
{
if (cache.semaphore.Wait(0))
{
try
{
var dateObsolete = DateTime.Now + obsolete;
var dateQueryStart = DateTime.Now;
var data = await valueFactoryAsync(token);
var queryTime = DateTime.Now - dateQueryStart;
if (dateObsolete - DateTime.Now < minCacheTime)
dateObsolete = DateTime.Now + minCacheTime;
cache.Data = data;
cache.DateObsolete = dateObsolete;
cache.DateObsoleteTotal = dateObsolete + queryTime + minCacheTime;
}
catch
{
throw;
}
finally
{
cache.semaphore.Release();
}
}
else if (cache.DateObsoleteTotal < DateTime.Now)
{
if (await cache.semaphore.WaitAsync(semaphoreTimeout, token))
{
cache.semaphore.Release();
}
else
{
cache.semaphore.Release();
throw new TimeoutException("EfCacheL2.GetOrAddCache. Can't wait too long while getting updated cache");
}
}
}
return cache;
}
private static IEnumerable<T> ConvertToIEnumerable<T>(IEnumerable? data)
{
if (data is IEnumerable<T> list)
return list;
else if (data is IDictionary dictionary)
{
System.Diagnostics.Trace.TraceWarning($"ConvertToIEnumerable. Use keyless method on keyed cache. Type: {typeof(T).Name};");
return (IEnumerable<T>)dictionary.Values;
}
else
throw new NotSupportedException("cache.Data has wrong type.");
}
private static Dictionary<TKey, T> ConvertToDictionary<TKey, T>(IEnumerable? data, Func<T, TKey> keySelector)
where TKey : notnull
{
if (data is Dictionary<TKey, T> dictionary)
return dictionary;
else if (data is IEnumerable<T> enumerable)
{
System.Diagnostics.Trace.TraceWarning($"ConvertToDictionary. Use keyed method on keyless cache. Type: {typeof(T).Name};");
return enumerable.ToDictionary(keySelector);
}
else
throw new NotSupportedException("cache.Data has wrong type.");
}
/// <summary>
/// Кешировать запрос в List\<typeparamref name="T"\>.
/// Выборки по PK будут работать медленнее, чем при кешировании в виде словаря.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="query"></param>
/// <param name="tag">Метка кеша</param>
/// <param name="obsolescence">Период устаревания данных</param>
/// <returns></returns>
public static IEnumerable<T> FromCache<T>(this IQueryable<T> query, string tag, TimeSpan obsolescence)
{
IEnumerable factory ()
{
CountOfRequestsToDB++;
return query.ToList();
}
var cache = GetOrAddCache(tag, factory, obsolescence);
return ConvertToIEnumerable<T>(cache.Data);
}
/// <summary>
/// Асинхронно кешировать запрос в List\<typeparamref name="T"\>.
/// Выборки по PK будут работать медленнее, чем при кешировании в виде словаря.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="query"></param>
/// <param name="tag">Метка кеша</param>
/// <param name="obsolescence">Период устаревания данных</param>
/// <param name="token"></param>
/// <returns></returns>
public static async Task<IEnumerable<T>> FromCacheAsync<T>(this IQueryable<T> query, string tag, TimeSpan obsolescence, CancellationToken token = default)
{
async Task<IEnumerable> factory(CancellationToken token)
{
CountOfRequestsToDB++;
return await query.ToListAsync(token);
}
var cache = await GetOrAddCacheAsync(tag, factory, obsolescence, token);
return ConvertToIEnumerable<T>(cache.Data);
}
/// <summary>
/// Кешировать запрос в Dictionary\<typeparamref name="TKey", typeparamref name="T"\>.
/// </summary>
/// <typeparam name="TKey">тип ключа</typeparam>
/// <typeparam name="T">тип значения</typeparam>
/// <param name="query"></param>
/// <param name="tag">Метка кеша</param>
/// <param name="obsolescence">Период устаревания данных</param>
/// <param name="keySelector">Делегат получения ключа из записи</param>
/// <returns></returns>
/// <example>
///
/// </example>
public static Dictionary<TKey, T> FromCache<TKey, T>(this IQueryable<T> query, string tag, TimeSpan obsolescence, Func<T, TKey> keySelector)
where TKey: notnull
{
IEnumerable factory ()
{
CountOfRequestsToDB++;
return query.ToDictionary(keySelector);
}
var cache = GetOrAddCache(tag, factory, obsolescence);
return ConvertToDictionary(cache.Data, keySelector);
}
/// <summary>
/// Асинхронно кешировать запрос в Dictionary\<typeparamref name="TKey", typeparamref name="T"\>.
/// </summary>
/// <typeparam name="TKey">тип ключа</typeparam>
/// <typeparam name="T">тип значения</typeparam>
/// <param name="query"></param>
/// <param name="tag">Метка кеша</param>
/// <param name="obsolescence">Период устаревания данных</param>
/// <param name="keySelector">Делегат получения ключа из записи</param>
/// <param name="token"></param>
/// <returns></returns>
public static async Task<Dictionary<TKey, T>> FromCacheAsync<TKey, T>(this IQueryable<T> query, string tag, TimeSpan obsolescence, Func<T, TKey> keySelector, CancellationToken token = default)
where TKey : notnull
{
async Task<IEnumerable> factory(CancellationToken token)
{
CountOfRequestsToDB++;
return await query.ToDictionaryAsync(keySelector, token);
}
var cache = await GetOrAddCacheAsync(tag, factory, obsolescence, token);
return ConvertToDictionary(cache.Data, keySelector);
}
/// <summary>
/// Получить запись из кеша по ключу.
/// При отсутствии кеша создаст его для всех записей из query.
/// </summary>
/// <typeparam name="TKey">тип ключа</typeparam>
/// <typeparam name="T">тип значения</typeparam>
/// <param name="query"></param>
/// <param name="tag">Метка кеша</param>
/// <param name="obsolescence">Период устаревания данных</param>
/// <param name="keySelector">Делегат получения ключа из записи</param>
/// <param name="key"></param>
/// <returns></returns>
/// <exception cref="NotSupportedException">if cache contains trash</exception>
public static T? FromCacheGetValueOrDefault<TKey, T>(this IQueryable<T> query, string tag, TimeSpan obsolescence, Func<T, TKey> keySelector, TKey key)
where TKey : notnull
{
IEnumerable factory()
{
CountOfRequestsToDB++;
return query.ToDictionary(keySelector);
}
var cache = GetOrAddCache(tag, factory, obsolescence);
var data = cache.Data;
if (data is Dictionary<TKey, T> dictionary)
return dictionary.GetValueOrDefault(key);
else if (data is IEnumerable<T> enumerable)
{
System.Diagnostics.Trace.TraceWarning($"Use keyed method on keyless cache. Tag: {tag}, type: {typeof(T).Name};");
return enumerable.FirstOrDefault(v => keySelector(v).Equals(key));
}
else
throw new NotSupportedException("cache.Data has wrong type.");
}
/// <summary>
/// Асинхронно получить запись из кеша по ключу.
/// При отсутствии кеша создаст его для всех записей из query.
/// </summary>
/// <typeparam name="TKey">тип ключа</typeparam>
/// <typeparam name="T">тип значения</typeparam>
/// <param name="query"></param>
/// <param name="tag">Метка кеша</param>
/// <param name="obsolescence">Период устаревания данных</param>
/// <param name="keySelector">Делегат получения ключа из записи</param>
/// <param name="key"></param>
/// <param name="token"></param>
/// <returns></returns>
/// <exception cref="NotSupportedException">if cache contains trash</exception>
public static async Task<T?> FromCacheGetValueOrDefaultAsync<TKey, T>(this IQueryable<T> query, string tag, TimeSpan obsolescence, Func<T, TKey> keySelector, TKey key, CancellationToken token = default)
where TKey : notnull
{
async Task<IEnumerable> factory(CancellationToken token)
{
CountOfRequestsToDB++;
return await query.ToDictionaryAsync(keySelector, token);
}
var cache = await GetOrAddCacheAsync(tag, factory, obsolescence, token);
var data = cache.Data;
if (data is Dictionary<TKey, T> dictionary)
return dictionary.GetValueOrDefault(key);
else if (data is IEnumerable<T> enumerable)
{
System.Diagnostics.Trace.TraceWarning($"Use keyed method on keyless cache. Tag: {tag}, type: {typeof(T).Name};");
return enumerable.FirstOrDefault(v => keySelector(v).Equals(key));
}
else
throw new NotSupportedException("cache.Data has wrong type.");
}
public static void DropCache<T>(this IQueryable<T> query, string tag)
{
caches.Remove(tag, out var _);
}
}
#nullable disable
}

View File

@ -124,15 +124,6 @@ namespace AsbCloudInfrastructure.Services
return context.SaveChangesAsync(token); return context.SaveChangesAsync(token);
} }
public virtual Task<int> DeleteAsync(IEnumerable<int> ids, CancellationToken token = default)
{
var entities = dbSet.Where(e => ids.Contains(e.Id)).AsNoTracking();
if (entities == default)
return Task.FromResult(0);
dbSet.RemoveRange(entities);
return context.SaveChangesAsync(token);
}
public virtual TDto Convert(TModel src) => src.Adapt<TDto>(); public virtual TDto Convert(TModel src) => src.Adapt<TDto>();
public virtual TModel Convert(TDto src) => src.Adapt<TModel>(); public virtual TModel Convert(TDto src) => src.Adapt<TModel>();

View File

@ -0,0 +1,8 @@
{
"profiles": {
"WSL": {
"commandName": "WSL2",
"distributionName": ""
}
}
}