Merge pull request 'Хранение первой и последней операции в кеше (для оптимизации запроса на получение скважин на главной и в админке)' (#274) from fix/#33063323-export-all-entries-ggd into dev

Reviewed-on: http://test.digitaldrilling.ru:8080/DDrilling/AsbCloudServer/pulls/274
This commit is contained in:
Никита Фролов 2024-05-08 11:59:24 +05:00
commit 66345f50d7
4 changed files with 114 additions and 44 deletions

View File

@ -1,9 +1,9 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Requests;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Requests;
namespace AsbCloudApp.Repositories namespace AsbCloudApp.Repositories
{ {
@ -18,7 +18,7 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
IEnumerable<WellSectionTypeDto> GetSectionTypes(); IEnumerable<WellSectionTypeDto> GetSectionTypes();
/// <summary> /// <summary>
/// Получить страницу списка операций /// Получить страницу списка операций
/// </summary> /// </summary>
/// <param name="request"></param> /// <param name="request"></param>
@ -26,7 +26,7 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token); Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token);
/// <summary> /// <summary>
/// Получить страницу списка операций /// Получить страницу списка операций
/// </summary> /// </summary>
/// <param name="request"></param> /// <param name="request"></param>
@ -34,7 +34,7 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token); Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token);
/// <summary> /// <summary>
/// Получить статистику операции по скважине с группировкой по категориям /// Получить статистику операции по скважине с группировкой по категориям
/// </summary> /// </summary>
/// <param name="request"></param> /// <param name="request"></param>
@ -42,14 +42,14 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token); Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token);
/// <summary> /// <summary>
/// Добавить несколько операций /// Добавить несколько операций
/// </summary> /// </summary>
/// <param name="dtos"></param> /// <param name="dtos"></param>
/// <param name="deleteBeforeInsert"></param> /// <param name="deleteBeforeInsert"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos, bool deleteBeforeInsert, CancellationToken token); Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos, bool deleteBeforeInsert, CancellationToken token);
/// <summary> /// <summary>
/// Обновить существующую операцию /// Обновить существующую операцию
@ -75,13 +75,20 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<SectionByOperationsDto>> GetSectionsAsync(IEnumerable<int> idsWells, CancellationToken token); Task<IEnumerable<SectionByOperationsDto>> GetSectionsAsync(IEnumerable<int> idsWells, CancellationToken token);
/// <summary> /// <summary>
/// Получить диапазон дат выполнения операций /// Получить диапазон дат выполнения операций
/// </summary> /// </summary>
/// <param name="idWell"></param> /// <param name="idWell"></param>
/// <param name="idType"></param> /// <param name="idType"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken); Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken);
}
/// <summary>
/// Возвращает первую и последнюю фактическую операцию
/// </summary>
/// <param name="idWell"></param>
/// <returns></returns>
(WellOperationDto First, WellOperationDto Last)? GetFirstAndLastFact(int idWell);
}
} }

View File

@ -16,12 +16,12 @@ namespace AsbCloudInfrastructure.Repository
public class DepositRepository : IDepositRepository public class DepositRepository : IDepositRepository
{ {
private readonly IAsbCloudDbContext db; private readonly IAsbCloudDbContext db;
private readonly IWellService wellService; private readonly ITelemetryService telemetryService;
public DepositRepository(IAsbCloudDbContext db, IWellService wellService) public DepositRepository(IAsbCloudDbContext db, ITelemetryService telemetryService)
{ {
this.db = db; this.db = db;
this.wellService = wellService; this.telemetryService = telemetryService;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -112,8 +112,12 @@ namespace AsbCloudInfrastructure.Repository
{ {
var dto = well.Adapt<WellDto>(); var dto = well.Adapt<WellDto>();
dto.WellType = well.WellType.Caption; dto.WellType = well.WellType.Caption;
dto.LastTelemetryDate = wellService.GetLastTelemetryDate(well.Id)
.ToOffset(TimeSpan.FromHours(well.Timezone.Hours)); dto.LastTelemetryDate = DateTimeOffset.MinValue;
if (well.IdTelemetry != null)
dto.LastTelemetryDate = telemetryService.GetDatesRange(well.IdTelemetry.Value).To;
dto.Cluster = gCluster.Key.Caption; dto.Cluster = gCluster.Key.Caption;
dto.Deposit = gDeposit.Key.Caption; dto.Deposit = gDeposit.Key.Caption;
return dto; return dto;

View File

@ -20,6 +20,7 @@ namespace AsbCloudInfrastructure.Repository;
public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, WellOperation>, public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, WellOperation>,
IWellOperationRepository IWellOperationRepository
{ {
private const string cacheKeyWellOperations = "FirstAndLastFactWellsOperations";
private readonly IMemoryCache memoryCache; private readonly IMemoryCache memoryCache;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
private readonly IWellService wellService; private readonly IWellService wellService;
@ -148,14 +149,26 @@ public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, Well
await DeleteRangeAsync(existingOperationIds, token); await DeleteRangeAsync(existingOperationIds, token);
return await InsertRangeAsync(dtos, token); var result = await InsertRangeAsync(dtos, token);
if (result > 0)
memoryCache.Remove(cacheKeyWellOperations);
return result;
} }
public override Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token) public override async Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token)
{ {
EnsureValidWellOperations(dtos); EnsureValidWellOperations(dtos);
return base.UpdateRangeAsync(dtos, token); var result = await base.UpdateRangeAsync(dtos, token);
if (result > 0)
memoryCache.Remove(cacheKeyWellOperations);
return result;
} }
private static void EnsureValidWellOperations(IEnumerable<WellOperationDto> dtos) private static void EnsureValidWellOperations(IEnumerable<WellOperationDto> dtos)
@ -350,6 +363,53 @@ public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, Well
}; };
} }
public (WellOperationDto First, WellOperationDto Last)? GetFirstAndLastFact(int idWell)
{
var cachedDictionary = memoryCache.GetOrCreate(cacheKeyWellOperations, (entry) =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);
var query = dbContext.Set<WellOperation>()
.Where(o => o.IdType == WellOperation.IdOperationTypeFact)
.GroupBy(o => o.IdWell)
.Select(group => new
{
IdWell = group.Key,
FirstFact = group.OrderBy(o => o.DateStart).First(),
LastFact = group.OrderBy(o => o.DateStart).Last(),
});
var entities = query.ToArray();
var dictionary = entities.ToDictionary(s => s.IdWell, s => (Convert(s.FirstFact), Convert(s.LastFact)));
entry.Value = dictionary;
return dictionary;
})!;
var firstAndLast = cachedDictionary.GetValueOrDefault(idWell);
return firstAndLast;
}
public override async Task<int> DeleteAsync(int id, CancellationToken token)
{
var result = await base.DeleteAsync(id, token);
if (result > 0)
memoryCache.Remove(cacheKeyWellOperations);
return result;
}
public override async Task<int> DeleteRangeAsync(IEnumerable<int> ids, CancellationToken token)
{
var result = await base.DeleteRangeAsync(ids, token);
if (result > 0)
memoryCache.Remove(cacheKeyWellOperations);
return result;
}
protected override WellOperation Convert(WellOperationDto src) protected override WellOperation Convert(WellOperationDto src)
{ {
var entity = src.Adapt<WellOperation>(); var entity = src.Adapt<WellOperation>();

View File

@ -273,9 +273,8 @@ namespace AsbCloudInfrastructure.Services
if (entity.Timezone is null) if (entity.Timezone is null)
dto.Timezone = GetTimezone(entity.Id); dto.Timezone = GetTimezone(entity.Id);
dto.StartDate = dbContext.WellOperations.Where(e => e.IdType == WellOperation.IdOperationTypeFact) dto.StartDate = wellOperationRepository
.AsNoTracking() .GetFirstAndLastFact(entity.Id)?.First?.DateStart;
.MinOrDefault(e => e.DateStart)?.ToRemoteDateTime(dto.Timezone.Hours);
dto.WellType = entity.WellType.Caption; dto.WellType = entity.WellType.Caption;
dto.Cluster = entity.Cluster.Caption; dto.Cluster = entity.Cluster.Caption;
dto.Deposit = entity.Cluster.Deposit.Caption; dto.Deposit = entity.Cluster.Deposit.Caption;