diff --git a/AsbCloudApp/Data/TelemetryDto.cs b/AsbCloudApp/Data/TelemetryDto.cs index 221e10dd..df55e879 100644 --- a/AsbCloudApp/Data/TelemetryDto.cs +++ b/AsbCloudApp/Data/TelemetryDto.cs @@ -2,11 +2,15 @@ namespace AsbCloudApp.Data { - public class TelemetryDto : IId + public class TelemetryBaseDto : IId { public int Id { get; set; } public string RemoteUid { get; set; } public TelemetryInfoDto Info { get; set; } + } + + public class TelemetryDto : TelemetryBaseDto + { public int? IdWell { get; set; } public WellInfoDto Well { get; set; } } diff --git a/AsbCloudApp/Data/WellDto.cs b/AsbCloudApp/Data/WellDto.cs index a7a235cf..f3843eaa 100644 --- a/AsbCloudApp/Data/WellDto.cs +++ b/AsbCloudApp/Data/WellDto.cs @@ -20,7 +20,7 @@ namespace AsbCloudApp.Data public int IdState { get; set; } public DateTime LastTelemetryDate { get; set; } public int? IdTelemetry { get; set; } - public TelemetryDto Telemetry { get; set; } + public TelemetryBaseDto Telemetry { get; set; } public IEnumerable Companies { get; set; } } } diff --git a/AsbCloudApp/Services/ICrudService.cs b/AsbCloudApp/Services/ICrudService.cs index 96034159..aa1f8b41 100644 --- a/AsbCloudApp/Services/ICrudService.cs +++ b/AsbCloudApp/Services/ICrudService.cs @@ -7,7 +7,7 @@ namespace AsbCloudApp.Services public interface ICrudService where Tdto : Data.IId { - List Includes { get; } + ISet Includes { get; } Task InsertAsync(Tdto newItem, CancellationToken token = default); Task InsertRangeAsync(IEnumerable newItems, CancellationToken token = default); Task> GetAllAsync(CancellationToken token = default); diff --git a/AsbCloudApp/Tree.cs b/AsbCloudApp/Tree.cs new file mode 100644 index 00000000..6e854954 --- /dev/null +++ b/AsbCloudApp/Tree.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AsbCloudApp +{ + public class Tree : Dictionary> + { + public Tree() + {} + + public Tree(T key, Tree node = null) + { + Add(key, node); + } + + public Tree(Tree other) + :base(other) + {} + + public Tree(IEnumerable keys) + { + foreach (var key in keys) + Add(key); + } + + public void Add(T key) => Add(key, null); + } +} diff --git a/AsbCloudDb/Model/AsbCloudDbContext.cs b/AsbCloudDb/Model/AsbCloudDbContext.cs index 62c3d27a..42fb6a2e 100644 --- a/AsbCloudDb/Model/AsbCloudDbContext.cs +++ b/AsbCloudDb/Model/AsbCloudDbContext.cs @@ -437,27 +437,6 @@ namespace AsbCloudDb.Model }); }); - //modelBuilder.Entity(entity => - //{ - // entity.HasData(new List{ - // new ModeType{ Id = 1, Caption = "Нагрузка" }, - // new ModeType{ Id = 2, Caption = "Дифф. давление" }, - // new ModeType{ Id = 3, Caption = "Момент на ВСП" }, - // new ModeType{ Id = 4, Caption = "Обороты на ВСП" }, - // new ModeType{ Id = 5, Caption = "Расход" } - // }); - //}); - } - - public IQueryable GetWellsForCompany(int idCompany) - { - return from well in Wells - .Include(w => w.RelationCompaniesWells) - .ThenInclude(r => r.Company) - .Include(w => w.Cluster) - .ThenInclude(c => c.Deposit) - where well.RelationCompaniesWells.Any(c => c.IdCompany == idCompany) - select well; } public async Task<(DateTime From, DateTime To)> GetDatesRangeAsync(int idTelemetry, diff --git a/AsbCloudInfrastructure/Services/ClusterService.cs b/AsbCloudInfrastructure/Services/ClusterService.cs index fc2d11ee..e22eed2c 100644 --- a/AsbCloudInfrastructure/Services/ClusterService.cs +++ b/AsbCloudInfrastructure/Services/ClusterService.cs @@ -64,7 +64,7 @@ namespace AsbCloudInfrastructure.Services public async Task> GetClustersAsync(int idCompany, CancellationToken token = default) { - var entities = await db.GetWellsForCompany(idCompany) + var entities = await GetWellsForCompany(idCompany) .Select(e => e.Cluster) .Distinct() .AsNoTracking() @@ -79,7 +79,7 @@ namespace AsbCloudInfrastructure.Services public async Task> GetClustersAsync(int idCompany, int depositId, CancellationToken token = default) { - var entities = await db.GetWellsForCompany(idCompany) + var entities = await GetWellsForCompany(idCompany) .Select(e => e.Cluster) .Where(e => e.IdDeposit == depositId) .Distinct() @@ -95,7 +95,7 @@ namespace AsbCloudInfrastructure.Services public async Task> GetWellsAsync(int idCompany, int idCluster, CancellationToken token = default) { - var entities = await db.GetWellsForCompany(idCompany) + var entities = await GetWellsForCompany(idCompany) .Where(e => e.IdCluster == idCluster) .AsNoTracking() .ToListAsync(token) @@ -121,6 +121,16 @@ namespace AsbCloudInfrastructure.Services .GroupBy(c => c.Key.Deposit); } + private IQueryable GetWellsForCompany(int idCompany) + { + return db.Wells + .Include(w => w.RelationCompaniesWells) + .ThenInclude(r => r.Company) + .Include(w => w.Cluster) + .ThenInclude(c => c.Deposit) + .Where(w => w.RelationCompaniesWells.Any(c => c.IdCompany == idCompany)); + } + private IEnumerable CreateDepositDto(IEnumerable>>gDepositEntities) { return gDepositEntities.Select(gDeposit => new DepositDto diff --git a/AsbCloudInfrastructure/Services/CrudCacheServiceBase.cs b/AsbCloudInfrastructure/Services/CrudCacheServiceBase.cs index 6a04a50f..d35f767c 100644 --- a/AsbCloudInfrastructure/Services/CrudCacheServiceBase.cs +++ b/AsbCloudInfrastructure/Services/CrudCacheServiceBase.cs @@ -1,3 +1,4 @@ +using AsbCloudApp; using AsbCloudApp.Services; using AsbCloudDb.Model; using AsbCloudInfrastructure.Services.Cache; @@ -18,7 +19,7 @@ namespace AsbCloudInfrastructure.Services private readonly IAsbCloudDbContext db; private readonly CacheDb cacheDb; - public List Includes { get; } = new (); + public ISet Includes { get; } = new SortedSet(); protected CacheTable Cache { get { diff --git a/AsbCloudInfrastructure/Services/CrudServiceBase.cs b/AsbCloudInfrastructure/Services/CrudServiceBase.cs index 45375aef..ca4bc395 100644 --- a/AsbCloudInfrastructure/Services/CrudServiceBase.cs +++ b/AsbCloudInfrastructure/Services/CrudServiceBase.cs @@ -1,4 +1,5 @@ -using AsbCloudApp.Data; +using AsbCloudApp; +using AsbCloudApp.Data; using AsbCloudApp.Services; using AsbCloudDb.Model; using Mapster; @@ -18,7 +19,7 @@ namespace AsbCloudInfrastructure.Services protected readonly IAsbCloudDbContext context; protected readonly DbSet dbSet; - public List Includes { get; } = new List(); + public ISet Includes { get; } = new SortedSet(); public CrudServiceBase(IAsbCloudDbContext context) { diff --git a/AsbCloudInfrastructure/Services/SetpointsService.cs b/AsbCloudInfrastructure/Services/SetpointsService.cs index 7624d063..09ff2f3f 100644 --- a/AsbCloudInfrastructure/Services/SetpointsService.cs +++ b/AsbCloudInfrastructure/Services/SetpointsService.cs @@ -34,11 +34,9 @@ namespace AsbCloudInfrastructure.Services public SetpointsService(IAsbCloudDbContext db, CacheDb cacheDb, ITelemetryService telemetryService) { cacheSetpoints = cacheDb.GetCachedTable( - (AsbCloudDbContext)db, - new List { - nameof(SetpointsRequest.Author), - nameof(SetpointsRequest.Well), - }); + (AsbCloudDbContext)db, + nameof(SetpointsRequest.Author), + nameof(SetpointsRequest.Well)); this.telemetryService = telemetryService; } @@ -125,7 +123,6 @@ namespace AsbCloudInfrastructure.Services return 1; } - public SetpointsRequest Convert(SetpointsRequestDto src) { var entity = src.Adapt(); diff --git a/AsbCloudInfrastructure/Services/TelemetryService.cs b/AsbCloudInfrastructure/Services/TelemetryService.cs index 9c7d9c34..4f53e4f9 100644 --- a/AsbCloudInfrastructure/Services/TelemetryService.cs +++ b/AsbCloudInfrastructure/Services/TelemetryService.cs @@ -16,9 +16,7 @@ namespace AsbCloudInfrastructure.Services public class TelemetryService : ITelemetryService { private readonly CacheTable cacheTelemetry; - private readonly CacheTable cacheWells; - private readonly CacheTable cacheClusters; - private readonly CacheTable cacheDeposits; + private readonly CacheTable cacheWells;//TODO: use wellService insad of this private readonly IAsbCloudDbContext db; private readonly ITelemetryTracker telemetryTracker; private readonly ITimeZoneService timeZoneService; @@ -33,9 +31,12 @@ namespace AsbCloudInfrastructure.Services CacheDb cacheDb) { cacheTelemetry = cacheDb.GetCachedTable((AsbCloudDbContext)db); - cacheWells = cacheDb.GetCachedTable((AsbCloudDbContext)db); - cacheClusters = cacheDb.GetCachedTable((AsbCloudDbContext)db); - cacheDeposits = cacheDb.GetCachedTable((AsbCloudDbContext)db); + cacheWells = cacheDb.GetCachedTable( + (AsbCloudDbContext)db, + $"{nameof(Well.Cluster)}.{nameof(Cluster.Deposit)}", + nameof(Well.Telemetry), + $"{nameof(Well.RelationCompaniesWells)}.{nameof(RelationCompanyWell.Company)}", + nameof(Well.WellType)); this.db = db; this.telemetryTracker = telemetryTracker; this.timeZoneService = timeZoneService; @@ -185,21 +186,17 @@ namespace AsbCloudInfrastructure.Services if (well is null) return null; - - if (well.Latitude is not null && well.Longitude is not null) - return (well.Latitude ?? default, well.Longitude??default); - - var cluster = await cacheClusters.FirstOrDefaultAsync(c => c.Id == well.IdCluster, token) - .ConfigureAwait(false); - if (cluster.Latitude is not null && cluster.Longitude is not null) - return (cluster.Latitude ?? default, cluster.Longitude ?? default); - - var deposit = await cacheDeposits.FirstOrDefaultAsync(d => d.Id == cluster.IdDeposit, token) - .ConfigureAwait(false); - - if (deposit.Latitude is not null && deposit.Longitude is not null) - return (deposit.Latitude ?? default, deposit.Longitude ?? default); + var latitude = well.Latitude ?? + well.Cluster?.Latitude ?? + well.Cluster?.Deposit?.Latitude; + + var longitude = well.Longitude ?? + well.Cluster?.Longitude ?? + well.Cluster?.Deposit?.Longitude; + + if (latitude is not null && longitude is not null) + return ((double)latitude, (double)longitude); return null; } diff --git a/AsbCloudInfrastructure/Services/UserService.cs b/AsbCloudInfrastructure/Services/UserService.cs index ea379d55..da06089f 100644 --- a/AsbCloudInfrastructure/Services/UserService.cs +++ b/AsbCloudInfrastructure/Services/UserService.cs @@ -15,8 +15,7 @@ namespace AsbCloudInfrastructure.Services { private readonly CacheTable cacheUsers; private readonly CacheTable cacheRelationUserToRoles; - - public List Includes { get; } + public ISet Includes { get; } = new SortedSet(); public IUserRoleService RoleService { get; } public UserService(IAsbCloudDbContext context, CacheDb cacheDb, IUserRoleService roleService) diff --git a/AsbCloudInfrastructure/Services/WellService.cs b/AsbCloudInfrastructure/Services/WellService.cs index c8a03bb2..c459a277 100644 --- a/AsbCloudInfrastructure/Services/WellService.cs +++ b/AsbCloudInfrastructure/Services/WellService.cs @@ -3,7 +3,6 @@ using AsbCloudApp.Services; using AsbCloudDb.Model; using AsbCloudInfrastructure.Services.Cache; using Mapster; -using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; @@ -13,15 +12,32 @@ using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services { public class WellService : CrudCacheServiceBase, IWellService - { + { + private static readonly TypeAdapterConfig typeAdapterConfig = TypeAdapterConfig + .NewConfig() + .Ignore(dst => dst.Cluster, + dst => dst.RelationCompaniesWells, + dst => dst.Telemetry, + dst => dst.WellComposites, + dst => dst.WellCompositeSrcs, + dst => dst.WellOperations, + dst => dst.WellType) + .Config; + private readonly ITelemetryService telemetryService; private readonly CacheTable cacheRelationCompaniesWells; + private readonly CacheTable cacheCompanyWellTypes; public WellService(IAsbCloudDbContext db, CacheDb cacheDb, ITelemetryService telemetryService) :base(db, cacheDb) { this.telemetryService = telemetryService; cacheRelationCompaniesWells = cacheDb.GetCachedTable((AsbCloudDbContext)db, nameof(RelationCompanyWell.Company), nameof(RelationCompanyWell.Well)); + cacheCompanyWellTypes = cacheDb.GetCachedTable((AsbCloudDbContext)db); + Includes.Add($"{nameof(Well.Cluster)}.{nameof(Cluster.Deposit)}"); + Includes.Add(nameof(Well.Telemetry)); + Includes.Add($"{nameof(Well.RelationCompaniesWells)}.{nameof(RelationCompanyWell.Company)}"); + Includes.Add(nameof(Well.WellType)); } public DateTime GetLastTelemetryDate(int idWell) @@ -39,15 +55,36 @@ namespace AsbCloudInfrastructure.Services { var relations = await cacheRelationCompaniesWells .WhereAsync(r => r.IdCompany == idCompany, token); - var dtos = relations.Select(r => Convert(r.Well)); + + var wellsIds = relations.Select(r => r.IdWell); + var wells = await Cache.WhereAsync(w => wellsIds.Contains(w.Id)); + + var dtos = wells.Select(Convert); return dtos; } - public override Task InsertAsync(WellDto newItem, CancellationToken token = default) + public override async Task InsertAsync(WellDto dto, CancellationToken token = default) { - throw new NotImplementedException(); - implement this - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + if (dto.IdWellType is < 1 or > 2) + throw new ArgumentException("Тип скважины указан неправильно.", nameof(dto)); + + if (dto.IdState is < 0 or > 2) + throw new ArgumentException("Текущее состояние работы скважины указано неправильно.", nameof(dto)); + + if (dto.Id != 0 && await Cache.ContainsAsync(w => w.Id == dto.Id, token)) + throw new ArgumentException($"Нельзя повторно добавить скважину с id: {dto.Id}", nameof(dto)); + + var entity = Convert(dto); + + var result = await Cache.InsertAsync(entity, token); + + if (dto.Companies.Any()) + { + var newRelations = dto.Companies.Select(c => new RelationCompanyWell { IdWell = result.Id, IdCompany = c.Id }); + await cacheRelationCompaniesWells.InsertAsync(newRelations, token); + } + + return result.Id; } public override Task InsertRangeAsync(IEnumerable dtos, CancellationToken token) @@ -69,7 +106,16 @@ namespace AsbCloudInfrastructure.Services var entity = Convert(dto); - var oldRelations = await cacheRelationCompaniesWells.FirstOrDefaultAsync(w => w.Id == idWell, token); + var oldRelations = await cacheRelationCompaniesWells + .WhereAsync(r => r.IdWell == idWell, token); + + if(dto.Companies.Count() != oldRelations.Count() || + dto.Companies.Any(c => !oldRelations.Any(oldC => oldC.IdCompany == c.Id))) + { + await cacheRelationCompaniesWells.RemoveAsync(r => r.IdWell == idWell, token); + var newRelations = dto.Companies.Select(c=> new RelationCompanyWell {IdWell = idWell, IdCompany = c.Id }); + await cacheRelationCompaniesWells.InsertAsync(newRelations, token); + } var result = await Cache.UpsertAsync(entity, token); return result; @@ -127,9 +173,21 @@ namespace AsbCloudInfrastructure.Services return clusterWells.Select(w => w.Id); } + protected override Well Convert(WellDto dto) + { + var entity = dto.Adapt(typeAdapterConfig); + //dto.WellType = entity.WellType?.Caption; + //dto.Cluster = entity.Cluster?.Caption; + //dto.Deposit = entity.Cluster?.Deposit?.Caption; + //dto.LastTelemetryDate = GetLastTelemetryDate(entity.Id); + //dto.Companies = GetCompanies(entity.Id); + return entity; + } + protected override WellDto Convert(Well entity) { var dto = base.Convert(entity); + dto.WellType = entity.WellType?.Caption; dto.Cluster = entity.Cluster?.Caption; dto.Deposit = entity.Cluster?.Deposit?.Caption; dto.LastTelemetryDate = GetLastTelemetryDate(entity.Id); @@ -140,6 +198,8 @@ namespace AsbCloudInfrastructure.Services private CompanyDto Convert(Company entity) { var dto = entity.Adapt(); + dto.CompanyTypeCaption = entity.CompanyType?.Caption + ?? cacheCompanyWellTypes.FirstOrDefault(c => c.Id == entity.IdCompanyType).Caption; return dto; } }