DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/WellService.cs

342 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AsbCloudApp.Data;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.EfCache;
using AsbCloudInfrastructure.Repository;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
public class WellService : CrudCacheRepositoryBase<WellDto, Well>, IWellService
{
private const string relationCompaniesWellsCacheTag = "RelationCompaniesWells";
private static readonly TimeSpan relationCompaniesWellsCacheObsolence = TimeSpan.FromMinutes(15);
private readonly ITelemetryService telemetryService;
private readonly ICrudRepository<CompanyTypeDto> companyTypesService;
private readonly ITimezoneService timezoneService;
private readonly IWellOperationRepository wellOperationRepository;
public ITelemetryService TelemetryService => telemetryService;
private static IQueryable<Well> MakeQueryWell(DbSet<Well> dbSet)
=> dbSet
.Include(w => w.Cluster)
.ThenInclude(c => c.Deposit)
.Include(w => w.Telemetry)
.Include(w => w.WellType)
.Include(w => w.RelationCompaniesWells)
.ThenInclude(r => r.Company);
public WellService(IAsbCloudDbContext db, IMemoryCache memoryCache, ITelemetryService telemetryService, ITimezoneService timezoneService)
: base(db, memoryCache, MakeQueryWell)
{
this.telemetryService = telemetryService;
this.timezoneService = timezoneService;
this.wellOperationRepository = new WellOperationRepository(db, memoryCache, this);
companyTypesService = new CrudCacheRepositoryBase<CompanyTypeDto, CompanyType>(dbContext, memoryCache);
}
private IEnumerable<RelationCompanyWell> GetCacheRelationCompanyWell()
=> dbContext.RelationCompaniesWells
.Include(r => r.Company)
.Include(r => r.Well)
.FromCache(relationCompaniesWellsCacheTag, relationCompaniesWellsCacheObsolence);
private Task<IEnumerable<RelationCompanyWell>> GetCacheRelationCompanyWellAsync(CancellationToken token)
=> dbContext.RelationCompaniesWells
.Include(r => r.Company)
.Include(r => r.Well)
.FromCacheAsync(relationCompaniesWellsCacheTag, relationCompaniesWellsCacheObsolence, token);
private void DropCacheRelationCompanyWell()
=> dbContext.RelationCompaniesWells.DropCache(relationCompaniesWellsCacheTag);
public DateTimeOffset GetLastTelemetryDate(int idWell)
{
var well = GetOrDefault(idWell);
if (well?.IdTelemetry is null)
return DateTimeOffset.MinValue;
var lastTelemetryDate = telemetryService.GetLastTelemetryDate((int)well.IdTelemetry);
return lastTelemetryDate;
}
public async Task<IEnumerable<WellDto>> GetWellsByCompanyAsync(int idCompany, CancellationToken token)
{
var relationsCache = await GetCacheRelationCompanyWellAsync(token);
var wellsIds = relationsCache
.Where(r => r.IdCompany == idCompany)
.Select(r => r.IdWell);
var wellsDtos = (await GetCacheAsync(token))
.Where(w => wellsIds.Contains(w.Id))
.Select(Convert);
return wellsDtos;
}
public override async Task<int> InsertAsync(WellDto dto, CancellationToken token = default)
{
if (dto.IdWellType is < 1 or > 2)
throw new ArgumentInvalidException("Тип скважины указан неправильно.", nameof(dto));
if (dto.IdState is < 0 or > 2)
throw new ArgumentInvalidException("Текущее состояние работы скважины указано неправильно.", nameof(dto));
if (dto.Id != 0 && (await GetCacheAsync(token)).Any(w => w.Id == dto.Id))
throw new ArgumentInvalidException($"Нельзя повторно добавить скважину с id: {dto.Id}", nameof(dto));
var entity = Convert(dto);
var result = await base.InsertAsync(dto, token);
if (dto.Companies.Any())
{
var newRelations = dto.Companies.Select(c => new RelationCompanyWell { IdWell = result, IdCompany = c.Id });
dbContext.RelationCompaniesWells.AddRange(newRelations);
await dbContext.SaveChangesAsync(token);
DropCacheRelationCompanyWell();
}
return result;
}
public override Task<int> InsertRangeAsync(IEnumerable<WellDto> dtos, CancellationToken token)
{
throw new NotImplementedException();
}
public override async Task<int> UpdateAsync(WellDto dto,
CancellationToken token = default)
{
if (dto.IdWellType is < 1 or > 2)
throw new ArgumentInvalidException("Тип скважины указан неправильно.", nameof(dto));
if (dto.IdState is < 0 or > 2)
throw new ArgumentInvalidException("Текущее состояние работы скважины указано неправильно.", nameof(dto));
var oldRelations = (await GetCacheRelationCompanyWellAsync(token))
.Where(r => r.IdWell == dto.Id);
if (dto.Companies.Count() != oldRelations.Count() ||
dto.Companies.Any(c => !oldRelations.Any(oldC => oldC.IdCompany == c.Id)))
{
dbContext.RelationCompaniesWells
.RemoveRange(dbContext.RelationCompaniesWells
.Where(r => r.IdWell == dto.Id));
var newRelations = dto.Companies.Select(c => new RelationCompanyWell { IdWell = dto.Id, IdCompany = c.Id });
dbContext.RelationCompaniesWells.AddRange(newRelations);
}
var result = await base.UpdateAsync(dto, token);
return result;
}
public bool IsCompanyInvolvedInWell(int idCompany, int idWell)
=> GetCacheRelationCompanyWell()
.Any(r => r.IdWell == idWell && r.IdCompany == idCompany);
public async Task<bool> IsCompanyInvolvedInWellAsync(int idCompany, int idWell, CancellationToken token)
=> (await GetCacheRelationCompanyWellAsync(token))
.Any(r => r.IdWell == idWell && r.IdCompany == idCompany);
public async Task<string> GetWellCaptionByIdAsync(int idWell, CancellationToken token)
{
var entity = await GetOrDefaultAsync(idWell, token).ConfigureAwait(false);
return entity!.Caption;
}
public async Task<IEnumerable<CompanyDto>> GetCompaniesAsync(int idWell, CancellationToken token)
{
var relations = (await GetCacheRelationCompanyWellAsync(token))
.Where(r => r.IdWell == idWell);
var dtos = relations.Select(r => Convert(r.Company));
return dtos;
}
public string GetStateText(int state)
{
return state switch
{
1 => "В работе",
2 => "Завершена",
_ => "Неизвестно",
};
}
public async Task<IEnumerable<int>> GetClusterWellsIdsAsync(int idWell, CancellationToken token)
{
var well = await GetOrDefaultAsync(idWell, token);
if (well is null)
return null;
var cache = await GetCacheAsync(token);
var clusterWellsIds = cache
.Where((w) => w.IdCluster == well.IdCluster)
.Select(w => w.Id);
return clusterWellsIds;
}
protected override Well Convert(WellDto dto)
{
var entity = dto.Adapt<Well>();
entity.IdTelemetry = entity.IdTelemetry ?? dto.IdTelemetry ?? dto.Telemetry?.Id;
if (dto.Timezone is null)
entity.Timezone = GetTimezone(dto.Id)
.Adapt<SimpleTimezone>();
return entity;
}
protected override WellDto Convert(Well entity)
{
if (entity is null)
return null;
var dto = base.Convert(entity);
if (entity.Timezone is null)
dto.Timezone = GetTimezone(entity.Id);
dto.StartDate = wellOperationRepository.FirstOperationDate(entity.Id)?.ToRemoteDateTime(dto.Timezone.Hours);
dto.WellType = entity.WellType?.Caption;
dto.Cluster = entity.Cluster?.Caption;
dto.Deposit = entity.Cluster?.Deposit?.Caption;
if (entity.IdTelemetry is not null)
dto.LastTelemetryDate = telemetryService.GetLastTelemetryDate((int)entity.IdTelemetry);
dto.Companies = entity.RelationCompaniesWells
.Select(r => Convert(r.Company))
.ToList();
return dto;
}
private CompanyDto Convert(Company entity)
{
var dto = entity.Adapt<CompanyDto>();
dto.CompanyTypeCaption = entity.CompanyType?.Caption
?? companyTypesService.GetOrDefault(entity.IdCompanyType).Caption;
return dto;
}
public async Task EnshureTimezonesIsSetAsync(CancellationToken token)
{
var cache = await GetCacheAsync(token);
if (!cache.Any(w => w.Timezone is null))
return;
var defaultTimeZone = new SimpleTimezone
{
Hours = 5,
IsOverride = false,
TimezoneId = "Assumed",
};
await dbSet.Where(w => w.Timezone == null)
.ForEachAsync(w => w.Timezone = defaultTimeZone, token);
await dbContext.SaveChangesAsync(token);
DropCache();
}
public SimpleTimezoneDto GetTimezone(int idWell)
{
var well = GetOrDefault(idWell);
if (well == null)
throw new ArgumentInvalidException($"idWell: {idWell} does not exist.", nameof(idWell));
return GetTimezone(well);
}
private SimpleTimezoneDto GetTimezone(WellDto wellDto)
{
if (wellDto.Timezone is not null)
return wellDto.Timezone;
if (wellDto.Telemetry is not null)
{
var timezone = telemetryService.GetTimezone(wellDto.Telemetry.Id);
if (timezone is not null)
return timezone;
}
var well = GetQuery().FirstOrDefault(w => w.Id == wellDto.Id);
var point = GetCoordinates(well);
if (point is not null)
{
if (point.Timezone is not null)
{
return point.Timezone.Adapt<SimpleTimezoneDto>();
}
if (point.Latitude is not null & point.Longitude is not null)
{
var timezone = timezoneService.GetByCoordinates((double)point.Latitude, (double)point.Longitude);
if (timezone is not null)
{
return timezone;
}
}
}
throw new Exception($"Can't find timezone for well {wellDto.Caption} id: {wellDto.Id}");
}
private static AsbCloudDb.Model.IMapPoint GetCoordinates(Well well)
{
if (well is null)
throw new ArgumentNullException(nameof(well));
if (well.Latitude is not null & well.Longitude is not null)
return well;
if (well.IdCluster is null)
throw new Exception($"Can't find coordinates of well {well.Caption} id: {well.Id}");
var cluster = well.Cluster;
if (cluster.Latitude is not null & cluster.Longitude is not null)
return cluster;
if (cluster.Deposit is null)
throw new Exception($"Can't find coordinates of well by cluster {cluster.Caption} id: {cluster.Id}");
var deposit = cluster.Deposit;
if (deposit.Latitude is not null & deposit.Longitude is not null)
return deposit;
throw new Exception($"Can't find coordinates of well by deposit {deposit.Caption} id: {deposit.Id}");
}
public DatesRangeDto GetDatesRange(int idWell)
{
var well = GetOrDefault(idWell);
if (well is null)
throw new Exception($"Well id: {idWell} does not exist.");
if (well.IdTelemetry is null)
throw new KeyNotFoundException($"Well id: {idWell} does not contain telemetry.");
return telemetryService.GetDatesRange((int)well.IdTelemetry);
}
}
}