forked from ddrilling/AsbCloudServer
This commit is contained in:
commit
5041b30686
@ -1,4 +1,6 @@
|
|||||||
namespace AsbCloudApp.Data.SAUB
|
using AsbCloudDb.Model;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Data.SAUB
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Пользователь панели оператора
|
/// Пользователь панели оператора
|
||||||
@ -27,5 +29,26 @@
|
|||||||
/// Уровень доступа
|
/// Уровень доступа
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Level { get; set; }
|
public int Level { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Собрать отображаемое имя пользователя
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string MakeDisplayName()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(Surname))
|
||||||
|
{
|
||||||
|
var s = Surname;
|
||||||
|
if (!string.IsNullOrEmpty(Name))
|
||||||
|
{
|
||||||
|
s += $"{Name[0]}.";
|
||||||
|
if (!string.IsNullOrEmpty(Patronymic))
|
||||||
|
s += $" {Patronymic[0]}.";
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return $"User #{Id}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,33 @@
|
|||||||
using AsbCloudApp.Data.SAUB;
|
using AsbCloudApp.Data.SAUB;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
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>
|
||||||
/// сервис пользователей телеметрии
|
/// сервис пользователей телеметрии
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ITelemetryUserService
|
public interface ITelemetryUserService
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// get user by ids
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idTelemetry"></param>
|
||||||
|
/// <param name="idUser"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TelemetryUserDto? GetOrDefault(int idTelemetry, int idUser);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// get users by id telemetry and predicate
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idTelemetry"></param>
|
||||||
|
/// <param name="predicate"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IEnumerable<TelemetryUserDto> GetUsers(int idTelemetry, Func<TelemetryUserDto, bool>? predicate = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// получает и сохраняет/обновляет список пользователей панели оператора
|
/// получает и сохраняет/обновляет список пользователей панели оператора
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -19,4 +37,5 @@ namespace AsbCloudApp.Services
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task UpsertAsync(string uid, IEnumerable<TelemetryUserDto> dtos, CancellationToken token = default);
|
Task UpsertAsync(string uid, IEnumerable<TelemetryUserDto> dtos, CancellationToken token = default);
|
||||||
}
|
}
|
||||||
|
#nullable disable
|
||||||
}
|
}
|
44
AsbCloudInfrastructure/CacheExtentions.cs
Normal file
44
AsbCloudInfrastructure/CacheExtentions.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using AsbCloudDb.Model;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
public static class MemoryCacheExtentions
|
||||||
|
{
|
||||||
|
private static readonly TimeSpan CacheOlescence = TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
|
public static Task<IEnumerable<T>> GetOrCreateBasicAsync<T>(this IMemoryCache memoryCache, IAsbCloudDbContext dbContext, CancellationToken token)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
var cacheTag = typeof(T).FullName;
|
||||||
|
var cache = memoryCache.GetOrCreateAsync(cacheTag, async (cacheEntry) => {
|
||||||
|
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
||||||
|
cacheEntry.SlidingExpiration = CacheOlescence;
|
||||||
|
|
||||||
|
var entities = await dbContext.Set<T>().ToArrayAsync(token);
|
||||||
|
return entities.AsEnumerable();
|
||||||
|
});
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<T> GetOrCreateBasic<T>(this IMemoryCache memoryCache, IAsbCloudDbContext dbContext)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
var cacheTag = typeof(T).FullName;
|
||||||
|
var cache = memoryCache.GetOrCreate(cacheTag, cacheEntry => {
|
||||||
|
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
||||||
|
cacheEntry.SlidingExpiration = CacheOlescence;
|
||||||
|
|
||||||
|
var entities = dbContext.Set<T>().ToArray();
|
||||||
|
return entities.AsEnumerable();
|
||||||
|
});
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,6 @@ using AsbCloudDb.Model;
|
|||||||
using AsbCloudDb.Model.Subsystems;
|
using AsbCloudDb.Model.Subsystems;
|
||||||
using AsbCloudInfrastructure.Repository;
|
using AsbCloudInfrastructure.Repository;
|
||||||
using AsbCloudInfrastructure.Services;
|
using AsbCloudInfrastructure.Services;
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using AsbCloudInfrastructure.Services.DailyReport;
|
using AsbCloudInfrastructure.Services.DailyReport;
|
||||||
using AsbCloudInfrastructure.Services.DetectOperations;
|
using AsbCloudInfrastructure.Services.DetectOperations;
|
||||||
using AsbCloudInfrastructure.Services.DrillingProgram;
|
using AsbCloudInfrastructure.Services.DrillingProgram;
|
||||||
@ -16,10 +15,10 @@ using AsbCloudInfrastructure.Services.SAUB;
|
|||||||
using AsbCloudInfrastructure.Services.Subsystems;
|
using AsbCloudInfrastructure.Services.Subsystems;
|
||||||
using AsbCloudInfrastructure.Services.WellOperationService;
|
using AsbCloudInfrastructure.Services.WellOperationService;
|
||||||
using AsbCloudInfrastructure.Validators;
|
using AsbCloudInfrastructure.Validators;
|
||||||
using DocumentFormat.OpenXml.Spreadsheet;
|
|
||||||
using FluentValidation.AspNetCore;
|
using FluentValidation.AspNetCore;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
@ -94,6 +93,7 @@ namespace AsbCloudInfrastructure
|
|||||||
// TODO: переместить FluentValidation в описание моделей
|
// TODO: переместить FluentValidation в описание моделей
|
||||||
services.AddFluentValidationClientsideAdapters();
|
services.AddFluentValidationClientsideAdapters();
|
||||||
|
|
||||||
|
services.AddMemoryCache();
|
||||||
services.AddScoped<IAsbCloudDbContext>(provider => provider.GetService<AsbCloudDbContext>());
|
services.AddScoped<IAsbCloudDbContext>(provider => provider.GetService<AsbCloudDbContext>());
|
||||||
services.AddScoped<IEmailService, EmailService>();
|
services.AddScoped<IEmailService, EmailService>();
|
||||||
|
|
||||||
@ -101,7 +101,6 @@ namespace AsbCloudInfrastructure
|
|||||||
services.AddHostedService<SubsystemOperationTimeBackgroundService>();
|
services.AddHostedService<SubsystemOperationTimeBackgroundService>();
|
||||||
services.AddHostedService<LimitingParameterBackgroundService>();
|
services.AddHostedService<LimitingParameterBackgroundService>();
|
||||||
services.AddSingleton(new WitsInfoService());
|
services.AddSingleton(new WitsInfoService());
|
||||||
services.AddSingleton(new CacheDb());
|
|
||||||
services.AddSingleton(new InstantDataRepository());
|
services.AddSingleton(new InstantDataRepository());
|
||||||
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(configuration));
|
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(configuration));
|
||||||
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(configuration));
|
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(configuration));
|
||||||
@ -143,21 +142,25 @@ namespace AsbCloudInfrastructure
|
|||||||
services.AddTransient<ICrudService<TelemetryDto>, CrudServiceBase<TelemetryDto, Telemetry>>(s =>
|
services.AddTransient<ICrudService<TelemetryDto>, CrudServiceBase<TelemetryDto, Telemetry>>(s =>
|
||||||
new CrudCacheServiceBase<TelemetryDto, Telemetry>(
|
new CrudCacheServiceBase<TelemetryDto, Telemetry>(
|
||||||
s.GetService<IAsbCloudDbContext>(),
|
s.GetService<IAsbCloudDbContext>(),
|
||||||
|
s.GetService<IMemoryCache>(),
|
||||||
dbSet => dbSet.Include(t => t.Well))); // может быть включен в сервис TelemetryService
|
dbSet => dbSet.Include(t => t.Well))); // может быть включен в сервис TelemetryService
|
||||||
services.AddTransient<ICrudService<DrillParamsDto>, DrillParamsService>();
|
services.AddTransient<ICrudService<DrillParamsDto>, DrillParamsService>();
|
||||||
services.AddTransient<ICrudService<DepositDto>, CrudCacheServiceBase<DepositDto, Deposit>>(s =>
|
services.AddTransient<ICrudService<DepositDto>, CrudCacheServiceBase<DepositDto, Deposit>>(s =>
|
||||||
new CrudCacheServiceBase<DepositDto, Deposit>(
|
new CrudCacheServiceBase<DepositDto, Deposit>(
|
||||||
s.GetService<IAsbCloudDbContext>(),
|
s.GetService<IAsbCloudDbContext>(),
|
||||||
|
s.GetService<IMemoryCache>(),
|
||||||
dbSet => dbSet.Include(d => d.Clusters)));
|
dbSet => dbSet.Include(d => d.Clusters)));
|
||||||
services.AddTransient<ICrudService<CompanyDto>, CrudCacheServiceBase<CompanyDto, Company>>(s =>
|
services.AddTransient<ICrudService<CompanyDto>, CrudCacheServiceBase<CompanyDto, Company>>(s =>
|
||||||
new CrudCacheServiceBase<CompanyDto, Company>(
|
new CrudCacheServiceBase<CompanyDto, Company>(
|
||||||
s.GetService<IAsbCloudDbContext>(),
|
s.GetService<IAsbCloudDbContext>(),
|
||||||
|
s.GetService<IMemoryCache>(),
|
||||||
dbSet => dbSet.Include(c => c.CompanyType)));
|
dbSet => dbSet.Include(c => c.CompanyType)));
|
||||||
|
|
||||||
services.AddTransient<ICrudService<CompanyTypeDto>, CrudCacheServiceBase<CompanyTypeDto, CompanyType>>();
|
services.AddTransient<ICrudService<CompanyTypeDto>, CrudCacheServiceBase<CompanyTypeDto, CompanyType>>();
|
||||||
services.AddTransient<ICrudService<ClusterDto>, CrudCacheServiceBase<ClusterDto, Cluster>>(s =>
|
services.AddTransient<ICrudService<ClusterDto>, CrudCacheServiceBase<ClusterDto, Cluster>>(s =>
|
||||||
new CrudCacheServiceBase<ClusterDto, Cluster>(
|
new CrudCacheServiceBase<ClusterDto, Cluster>(
|
||||||
s.GetService<IAsbCloudDbContext>(),
|
s.GetService<IAsbCloudDbContext>(),
|
||||||
|
s.GetService<IMemoryCache>(),
|
||||||
dbSet => dbSet
|
dbSet => dbSet
|
||||||
.Include(c => c.Wells)
|
.Include(c => c.Wells)
|
||||||
.Include(c => c.Deposit))); // может быть включен в сервис ClusterService
|
.Include(c => c.Deposit))); // может быть включен в сервис ClusterService
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.EfCache;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -21,16 +21,21 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
{
|
{
|
||||||
protected string CacheTag = typeof(TDto).Name;
|
protected string CacheTag = typeof(TDto).Name;
|
||||||
protected TimeSpan CacheOlescence = TimeSpan.FromMinutes(5);
|
protected TimeSpan CacheOlescence = TimeSpan.FromMinutes(5);
|
||||||
|
private readonly IMemoryCache memoryCache;
|
||||||
|
|
||||||
protected int KeySelector(TEntity entity) => entity.Id;
|
protected int KeySelector(TEntity entity) => entity.Id;
|
||||||
|
|
||||||
public CrudCacheServiceBase(IAsbCloudDbContext dbContext)
|
public CrudCacheServiceBase(IAsbCloudDbContext dbContext, IMemoryCache memoryCache)
|
||||||
: base(dbContext) { }
|
: base(dbContext)
|
||||||
|
{
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
|
}
|
||||||
|
|
||||||
public CrudCacheServiceBase(IAsbCloudDbContext dbContext, ISet<string> includes)
|
public CrudCacheServiceBase(IAsbCloudDbContext dbContext, IMemoryCache memoryCache, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
||||||
: base(dbContext, includes) { }
|
: base(dbContext, makeQuery)
|
||||||
|
{
|
||||||
public CrudCacheServiceBase(IAsbCloudDbContext dbContext, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
this.memoryCache = memoryCache;
|
||||||
: base(dbContext, makeQuery) { }
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override async Task<int> InsertAsync(TDto newItem, CancellationToken token)
|
public override async Task<int> InsertAsync(TDto newItem, CancellationToken token)
|
||||||
@ -103,16 +108,33 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Task<IEnumerable<TDto>> GetCacheAsync(CancellationToken token)
|
protected virtual Task<IEnumerable<TDto>> GetCacheAsync(CancellationToken token)
|
||||||
=> GetQuery()
|
{
|
||||||
.FromCacheAsync(CacheTag, CacheOlescence, Convert, token);
|
var cache = memoryCache.GetOrCreateAsync(CacheTag, async (cacheEntry) => {
|
||||||
|
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
||||||
|
cacheEntry.SlidingExpiration = CacheOlescence;
|
||||||
|
|
||||||
|
var entities = await GetQuery().ToArrayAsync(token);
|
||||||
|
var dtos = entities.Select(Convert);
|
||||||
|
return dtos.ToArray().AsEnumerable();
|
||||||
|
});
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual IEnumerable<TDto> GetCache()
|
protected virtual IEnumerable<TDto> GetCache()
|
||||||
=> GetQuery()
|
{
|
||||||
.FromCache(CacheTag, CacheOlescence, Convert);
|
var cache = memoryCache.GetOrCreate(CacheTag, cacheEntry => {
|
||||||
|
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
||||||
|
cacheEntry.SlidingExpiration= CacheOlescence;
|
||||||
|
|
||||||
|
var entities = GetQuery().ToArray();
|
||||||
|
var dtos = entities.Select(Convert);
|
||||||
|
return dtos.ToArray();
|
||||||
|
});
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void DropCache()
|
protected virtual void DropCache()
|
||||||
=> dbSet.DropCache(CacheTag);
|
=> memoryCache.Remove(CacheTag);
|
||||||
}
|
}
|
||||||
#nullable disable
|
#nullable disable
|
||||||
}
|
}
|
@ -31,20 +31,6 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
GetQuery = () => dbSet;
|
GetQuery = () => dbSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CrudServiceBase(IAsbCloudDbContext dbContext, ISet<string> includes)
|
|
||||||
{
|
|
||||||
this.dbContext = dbContext;
|
|
||||||
dbSet = dbContext.Set<TEntity>();
|
|
||||||
|
|
||||||
GetQuery = () =>
|
|
||||||
{
|
|
||||||
IQueryable<TEntity> query = dbSet;
|
|
||||||
foreach (var include in includes)
|
|
||||||
query = query.Include(include);
|
|
||||||
return query;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public CrudServiceBase(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
public CrudServiceBase(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
||||||
{
|
{
|
||||||
dbContext = context;
|
dbContext = context;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -14,14 +15,11 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
where TDto : AsbCloudApp.Data.IId, AsbCloudApp.Data.IWellRelated
|
where TDto : AsbCloudApp.Data.IId, AsbCloudApp.Data.IWellRelated
|
||||||
where TEntity : class, IId, IWellRelated
|
where TEntity : class, IId, IWellRelated
|
||||||
{
|
{
|
||||||
public CrudWellRelatedCacheServiceBase(IAsbCloudDbContext context)
|
public CrudWellRelatedCacheServiceBase(IAsbCloudDbContext context, IMemoryCache memoryCache)
|
||||||
: base(context) { }
|
: base(context, memoryCache) { }
|
||||||
|
|
||||||
public CrudWellRelatedCacheServiceBase(IAsbCloudDbContext dbContext, ISet<string> includes)
|
public CrudWellRelatedCacheServiceBase(IAsbCloudDbContext context, IMemoryCache memoryCache, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
||||||
: base(dbContext, includes) { }
|
: base(context, memoryCache, makeQuery) { }
|
||||||
|
|
||||||
public CrudWellRelatedCacheServiceBase(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
|
||||||
: base(context, makeQuery) { }
|
|
||||||
|
|
||||||
public async Task<IEnumerable<TDto>?> GetByIdWellAsync(int idWell, CancellationToken token)
|
public async Task<IEnumerable<TDto>?> GetByIdWellAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
@ -17,9 +17,6 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
public CrudWellRelatedServiceBase(IAsbCloudDbContext context)
|
public CrudWellRelatedServiceBase(IAsbCloudDbContext context)
|
||||||
: base(context) { }
|
: base(context) { }
|
||||||
|
|
||||||
public CrudWellRelatedServiceBase(IAsbCloudDbContext dbContext, ISet<string> includes)
|
|
||||||
: base(dbContext, includes) { }
|
|
||||||
|
|
||||||
public CrudWellRelatedServiceBase(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
public CrudWellRelatedServiceBase(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
||||||
: base(context, makeQuery) { }
|
: base(context, makeQuery) { }
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Repository
|
namespace AsbCloudInfrastructure.Repository
|
||||||
@ -10,8 +11,8 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
{
|
{
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
|
|
||||||
public SetpointsRequestRepository(IAsbCloudDbContext dbContext, IWellService wellService)
|
public SetpointsRequestRepository(IAsbCloudDbContext dbContext, IMemoryCache memoryCache, IWellService wellService)
|
||||||
: base(dbContext, q => q.Include(s => s.Author)
|
: base(dbContext, memoryCache, q => q.Include(s => s.Author)
|
||||||
.Include(s => s.Well))
|
.Include(s => s.Well))
|
||||||
{
|
{
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
|
@ -88,7 +88,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
|
|
||||||
foreach (var entity in entities)
|
foreach (var entity in entities)
|
||||||
{
|
{
|
||||||
if (!existingEntities.Any(e => e.DateTime == entity.DateTime))
|
if (!existingEntities.Any(e => e == entity.DateTime))
|
||||||
{
|
{
|
||||||
dbset.Add(entity);
|
dbset.Add(entity);
|
||||||
}
|
}
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.Cache
|
|
||||||
{
|
|
||||||
public class CacheDb
|
|
||||||
{
|
|
||||||
private readonly ConcurrentDictionary<string, CacheTableDataStore> cache =
|
|
||||||
new ConcurrentDictionary<string, CacheTableDataStore>();
|
|
||||||
|
|
||||||
public CacheTable<TEntity> GetCachedTable<TEntity>(DbContext context, params string[] includes)
|
|
||||||
where TEntity : class
|
|
||||||
=> GetCachedTable<TEntity>(context, new SortedSet<string>(includes));
|
|
||||||
|
|
||||||
public CacheTable<TEntity> GetCachedTable<TEntity>(DbContext context, ISet<string> includes = null)
|
|
||||||
where TEntity : class
|
|
||||||
{
|
|
||||||
var cacheItem = GetCacheTableDataStore<TEntity>();
|
|
||||||
var tableCache = new CacheTable<TEntity>(context, cacheItem, includes);
|
|
||||||
return tableCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CacheTable<TEntity> GetCachedTable<TEntity>(DbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> configureDbSet)
|
|
||||||
where TEntity : class
|
|
||||||
{
|
|
||||||
var cacheItem = GetCacheTableDataStore<TEntity>();
|
|
||||||
var tableCache = new CacheTable<TEntity>(context, cacheItem, configureDbSet);
|
|
||||||
return tableCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CacheTableDataStore GetCacheTableDataStore<TEntity>()
|
|
||||||
where TEntity : class
|
|
||||||
{
|
|
||||||
var nameOfTEntity = typeof(TEntity).FullName;
|
|
||||||
var cacheItem = cache.GetOrAdd(nameOfTEntity, (nameOfTEntity) => new CacheTableDataStore
|
|
||||||
{
|
|
||||||
NameOfTEntity = nameOfTEntity,
|
|
||||||
Entities = new List<TEntity>(),
|
|
||||||
});
|
|
||||||
return cacheItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DropAll() => cache.Clear();
|
|
||||||
|
|
||||||
public void Drop<TEntity>() => cache.Remove(typeof(TEntity).FullName, out _);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,449 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.Cache
|
|
||||||
{
|
|
||||||
public class CacheTable<TEntity> : IEnumerable<TEntity>
|
|
||||||
where TEntity : class
|
|
||||||
{
|
|
||||||
private const int semaphoreTimeout = 5_000;
|
|
||||||
private static readonly SemaphoreSlim semaphore = new(1);
|
|
||||||
private static readonly TimeSpan minPeriodRefresh = TimeSpan.FromSeconds(5);
|
|
||||||
private static readonly string nameOfTEntity = typeof(TEntity).Name;
|
|
||||||
|
|
||||||
private readonly CacheTableDataStore data;
|
|
||||||
private readonly Func<DbSet<TEntity>, IQueryable<TEntity>> configureDbSet;
|
|
||||||
private readonly List<TEntity> cached;
|
|
||||||
private readonly DbContext context;
|
|
||||||
private readonly DbSet<TEntity> dbSet;
|
|
||||||
|
|
||||||
internal CacheTable(DbContext context, CacheTableDataStore data, ISet<string> includes = null)
|
|
||||||
{
|
|
||||||
this.context = context;
|
|
||||||
this.data = data;
|
|
||||||
dbSet = context.Set<TEntity>();
|
|
||||||
|
|
||||||
if (includes?.Any() == true)
|
|
||||||
configureDbSet = (DbSet<TEntity> dbSet) =>
|
|
||||||
{
|
|
||||||
IQueryable<TEntity> result = dbSet;
|
|
||||||
foreach (var include in includes)
|
|
||||||
result = result.Include(include);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
cached = (List<TEntity>)data.Entities;
|
|
||||||
if ((cached.Count == 0) || data.IsObsolete)
|
|
||||||
Refresh(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CacheTable(DbContext context, CacheTableDataStore data,
|
|
||||||
Func<DbSet<TEntity>, IQueryable<TEntity>> configureDbSet = null)
|
|
||||||
{
|
|
||||||
this.context = context;
|
|
||||||
this.data = data;
|
|
||||||
this.configureDbSet = configureDbSet;
|
|
||||||
|
|
||||||
dbSet = context.Set<TEntity>();
|
|
||||||
|
|
||||||
cached = (List<TEntity>)data.Entities;
|
|
||||||
if ((cached.Count == 0) || data.IsObsolete)
|
|
||||||
Refresh(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TEntity this[int index]
|
|
||||||
{
|
|
||||||
get => cached.ElementAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Runs action like atomic operation.
|
|
||||||
/// wasFree is action argument indicates that semaphore was free.
|
|
||||||
/// It may be needed to avoid multiple operations like Refresh().
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">(wasFree) => {...}</param>
|
|
||||||
/// <returns>default if semaphoreTimeout. Or result of func(..)</returns>
|
|
||||||
private static T Sync<T>(Func<bool, T> func)
|
|
||||||
{
|
|
||||||
var wasFree = semaphore.CurrentCount > 0;
|
|
||||||
T result = default;
|
|
||||||
if (func is null || !semaphore.Wait(semaphoreTimeout))
|
|
||||||
return result;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result = func.Invoke(wasFree);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Trace.WriteLine($"{DateTime.Now:yyyy.MM.dd HH:mm:ss:fff} error in CacheTable<{nameOfTEntity}>.Sync()");
|
|
||||||
Trace.WriteLine(ex.Message);
|
|
||||||
Trace.WriteLine(ex.StackTrace);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Runs action like atomic operation.
|
|
||||||
/// wasFree is action argument indicates that semaphore was free.
|
|
||||||
/// It may be needed to avoid multiple operations like Refresh().
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">(wasFree) => {...}</param>
|
|
||||||
/// <returns>default if semaphoreTimeout. Or result of func(..)</returns>
|
|
||||||
private static async Task<T> SyncAsync<T>(Func<bool, CancellationToken, Task<T>> funcAsync,
|
|
||||||
CancellationToken token = default)
|
|
||||||
{
|
|
||||||
var wasFree = semaphore.CurrentCount > 0;
|
|
||||||
T result = default;
|
|
||||||
|
|
||||||
if (funcAsync is null || !await semaphore.WaitAsync(semaphoreTimeout, token).ConfigureAwait(false))
|
|
||||||
return result;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result = await funcAsync.Invoke(wasFree, token);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Trace.WriteLine(
|
|
||||||
$"{DateTime.Now:yyyy.MM.dd HH:mm:ss:fff} error in CacheTable<{nameOfTEntity}>.SyncAsync()");
|
|
||||||
Trace.WriteLine(ex.Message);
|
|
||||||
Trace.WriteLine(ex.StackTrace);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int InternalRefresh(bool force)
|
|
||||||
{
|
|
||||||
if (force || data.LastResreshDate + minPeriodRefresh < DateTime.Now)
|
|
||||||
{
|
|
||||||
cached.Clear();
|
|
||||||
IQueryable<TEntity> query = configureDbSet is null ? dbSet : configureDbSet(dbSet);
|
|
||||||
var entities = query.AsNoTracking().ToList();
|
|
||||||
//Trace.WriteLine($"CacheTable<{nameOfTEntity}> refresh");
|
|
||||||
cached.AddRange(entities);
|
|
||||||
data.LastResreshDate = DateTime.Now;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cached.Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<int> InternalRefreshAsync(bool force, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
if (force || data.LastResreshDate + minPeriodRefresh < DateTime.Now)
|
|
||||||
{
|
|
||||||
cached.Clear();
|
|
||||||
IQueryable<TEntity> query = configureDbSet is null ? dbSet : configureDbSet(dbSet);
|
|
||||||
var entities = await query.AsNoTracking()
|
|
||||||
.ToListAsync(token).ConfigureAwait(false);
|
|
||||||
//Trace.WriteLine($"CacheTable<{nameOfTEntity}> refreshAsync");
|
|
||||||
cached.AddRange(entities);
|
|
||||||
data.LastResreshDate = DateTime.Now;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cached.Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Refresh(bool force)
|
|
||||||
=> Sync((wasFree) => wasFree ? InternalRefresh(force) : 0);
|
|
||||||
|
|
||||||
public Task<int> RefreshAsync(bool force, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
return SyncAsync(
|
|
||||||
async (wasFree, token) =>
|
|
||||||
{
|
|
||||||
return wasFree ? await InternalRefreshAsync(force, token) : 0;
|
|
||||||
}, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(Func<TEntity, bool> predicate)
|
|
||||||
=> FirstOrDefault(predicate) != default;
|
|
||||||
|
|
||||||
public async Task<bool> ContainsAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
|
|
||||||
=> await FirstOrDefaultAsync(predicate, token) != default;
|
|
||||||
|
|
||||||
public TEntity GetOrCreate(Func<TEntity, bool> predicate, Func<TEntity> makeNew)
|
|
||||||
=> Sync(wasFree =>
|
|
||||||
{
|
|
||||||
var result = cached.FirstOrDefault(predicate);
|
|
||||||
if (result != default)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
InternalRefresh(true);
|
|
||||||
result = cached.FirstOrDefault(predicate);
|
|
||||||
if (result != default)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
var entry = dbSet.Add(makeNew());
|
|
||||||
context.SaveChanges();
|
|
||||||
InternalRefresh(true);
|
|
||||||
return entry.Entity;
|
|
||||||
});
|
|
||||||
|
|
||||||
public TEntity FirstOrDefault()
|
|
||||||
{
|
|
||||||
var result = cached.FirstOrDefault();
|
|
||||||
if (result != default)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
Refresh(false);
|
|
||||||
return cached.FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<TEntity> FirstOrDefaultAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
var result = cached.FirstOrDefault();
|
|
||||||
if (result != default)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
await RefreshAsync(false, token);
|
|
||||||
return cached.FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TEntity FirstOrDefault(Func<TEntity, bool> predicate)
|
|
||||||
{
|
|
||||||
var result = cached.FirstOrDefault(predicate);
|
|
||||||
if (result != default)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
Refresh(false);
|
|
||||||
return cached.FirstOrDefault(predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<TEntity> FirstOrDefaultAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
var result = cached.FirstOrDefault(predicate);
|
|
||||||
if (result != default)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
await RefreshAsync(false, token);
|
|
||||||
return cached.FirstOrDefault(predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<TEntity> Where(Func<TEntity, bool> predicate = default)
|
|
||||||
{
|
|
||||||
var result = (predicate != default)
|
|
||||||
? cached.Where(predicate)
|
|
||||||
: cached;
|
|
||||||
if (result.Any())
|
|
||||||
return result;
|
|
||||||
|
|
||||||
Refresh(false);
|
|
||||||
result = (predicate != default)
|
|
||||||
? cached.Where(predicate)
|
|
||||||
: cached;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<IEnumerable<TEntity>> WhereAsync(CancellationToken token = default) =>
|
|
||||||
WhereAsync(default, token);
|
|
||||||
|
|
||||||
public async Task<IEnumerable<TEntity>> WhereAsync(Func<TEntity, bool> predicate = default,
|
|
||||||
CancellationToken token = default)
|
|
||||||
{
|
|
||||||
var result = (predicate != default)
|
|
||||||
? cached.Where(predicate)
|
|
||||||
: cached;
|
|
||||||
if (result.Any())
|
|
||||||
return result;
|
|
||||||
|
|
||||||
await RefreshAsync(false, token);
|
|
||||||
result = (predicate != default)
|
|
||||||
? cached.Where(predicate)
|
|
||||||
: cached;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Upsert(TEntity entity)
|
|
||||||
{
|
|
||||||
if (entity == default)
|
|
||||||
return 0;
|
|
||||||
return Sync((wasFree) =>
|
|
||||||
{
|
|
||||||
if (dbSet.Contains(entity))
|
|
||||||
dbSet.Update(entity);
|
|
||||||
else
|
|
||||||
dbSet.Add(entity);
|
|
||||||
var affected = context.SaveChanges();
|
|
||||||
if (affected > 0)
|
|
||||||
InternalRefresh(true);
|
|
||||||
return affected;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<int> UpsertAsync(TEntity entity, CancellationToken token = default)
|
|
||||||
=> SyncAsync(async (wasFree, token) =>
|
|
||||||
{
|
|
||||||
if (dbSet.Contains(entity))
|
|
||||||
dbSet.Update(entity);
|
|
||||||
else
|
|
||||||
dbSet.Add(entity);
|
|
||||||
var affected = await context.SaveChangesAsync(token).ConfigureAwait(false);
|
|
||||||
if (affected > 0)
|
|
||||||
await InternalRefreshAsync(true, token);
|
|
||||||
return affected;
|
|
||||||
}, token);
|
|
||||||
|
|
||||||
public int Upsert(IEnumerable<TEntity> entities)
|
|
||||||
{
|
|
||||||
if (!entities.Any())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return Sync((wasFree) =>
|
|
||||||
{
|
|
||||||
foreach (var entity in entities)
|
|
||||||
{
|
|
||||||
if (dbSet.Contains(entity)) // TODO: это очень медленно
|
|
||||||
dbSet.Update(entity);
|
|
||||||
else
|
|
||||||
dbSet.Add(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
var affected = context.SaveChanges();
|
|
||||||
if (affected > 0)
|
|
||||||
InternalRefresh(true);
|
|
||||||
return affected;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<int> UpsertAsync(IEnumerable<TEntity> entities, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
if (!entities.Any())
|
|
||||||
return Task.FromResult(0);
|
|
||||||
|
|
||||||
return SyncAsync(async (wasFree, token) =>
|
|
||||||
{
|
|
||||||
var upsertedEntries = new List<TEntity>(entities.Count());
|
|
||||||
foreach (var entity in entities)
|
|
||||||
{
|
|
||||||
if (dbSet.Contains(entity))
|
|
||||||
dbSet.Update(entity);
|
|
||||||
else
|
|
||||||
dbSet.Add(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
var affected = await context.SaveChangesAsync(token).ConfigureAwait(false);
|
|
||||||
if (affected > 0)
|
|
||||||
await InternalRefreshAsync(true, token);
|
|
||||||
return affected;
|
|
||||||
}, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Remove(Func<TEntity, bool> predicate)
|
|
||||||
=> Sync(_ =>
|
|
||||||
{
|
|
||||||
dbSet.RemoveRange(dbSet.Where(predicate));
|
|
||||||
var affected = context.SaveChanges();
|
|
||||||
if (affected > 0)
|
|
||||||
InternalRefresh(true);
|
|
||||||
return affected;
|
|
||||||
});
|
|
||||||
|
|
||||||
public Task<int> RemoveAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
|
|
||||||
=> SyncAsync(async (wasFree, token) =>
|
|
||||||
{
|
|
||||||
dbSet.RemoveRange(dbSet.Where(predicate));
|
|
||||||
var affected = await context.SaveChangesAsync(token).ConfigureAwait(false);
|
|
||||||
if (affected > 0)
|
|
||||||
await InternalRefreshAsync(true, token);
|
|
||||||
return affected;
|
|
||||||
}, token);
|
|
||||||
|
|
||||||
public TEntity Insert(TEntity entity)
|
|
||||||
{
|
|
||||||
return Sync(_ =>
|
|
||||||
{
|
|
||||||
var entry = dbSet.Add(entity);
|
|
||||||
var affected = context.SaveChanges();
|
|
||||||
if (affected > 0)
|
|
||||||
InternalRefresh(true);
|
|
||||||
return entry.Entity;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<TEntity> InsertAsync(TEntity entity, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
return SyncAsync(async (wasFree, token) =>
|
|
||||||
{
|
|
||||||
var entry = dbSet.Add(entity);
|
|
||||||
var affected = await context.SaveChangesAsync(token).ConfigureAwait(false);
|
|
||||||
if (affected > 0)
|
|
||||||
await InternalRefreshAsync(true, token);
|
|
||||||
return entry.Entity;
|
|
||||||
}, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<TEntity> Insert(IEnumerable<TEntity> newEntities)
|
|
||||||
{
|
|
||||||
if (newEntities is null)
|
|
||||||
return null;
|
|
||||||
var count = newEntities.Count();
|
|
||||||
if (count == 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return Sync(_ =>
|
|
||||||
{
|
|
||||||
var entries = new List<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity>>(count);
|
|
||||||
foreach (var newEntity in newEntities)
|
|
||||||
{
|
|
||||||
var entry = dbSet.Add(newEntity);
|
|
||||||
entries.Add(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
var affected = context.SaveChanges();
|
|
||||||
if (affected > 0)
|
|
||||||
InternalRefresh(true);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return entries.Select(e => e.Entity);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<IEnumerable<TEntity>> InsertAsync(IEnumerable<TEntity> newEntities, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
if (newEntities is null)
|
|
||||||
return null;
|
|
||||||
var count = newEntities.Count();
|
|
||||||
if (count == 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return SyncAsync(async (wasFree, token) =>
|
|
||||||
{
|
|
||||||
var entries = new List<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity>>(count);
|
|
||||||
foreach (var newEntity in newEntities)
|
|
||||||
{
|
|
||||||
var entry = dbSet.Add(newEntity);
|
|
||||||
entries.Add(entry);
|
|
||||||
}
|
|
||||||
var affected = await context.SaveChangesAsync(token).ConfigureAwait(false);
|
|
||||||
if (affected > 0)
|
|
||||||
await InternalRefreshAsync(true, token);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return entries.Select(e => e.Entity);
|
|
||||||
}, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<TEntity> GetEnumerator() => Where().GetEnumerator();
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.Cache
|
|
||||||
{
|
|
||||||
class CacheTableDataStore
|
|
||||||
{
|
|
||||||
public string NameOfTEntity { get; set; }
|
|
||||||
public DateTime LastResreshDate { get; set; }
|
|
||||||
|
|
||||||
//public ISet<string> Includes { get; set; } //TODO: this prop change should update entities
|
|
||||||
public IEnumerable Entities { get; set; }
|
|
||||||
public TimeSpan ObsolesenceTime { get; set; } = TimeSpan.FromMinutes(15);
|
|
||||||
public bool IsObsolete => (DateTime.Now - LastResreshDate > ObsolesenceTime);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,7 @@
|
|||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Repository;
|
using AsbCloudInfrastructure.Repository;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -11,10 +12,8 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
{
|
{
|
||||||
public class FileCategoryService : CrudCacheServiceBase<FileCategoryDto, FileCategory>, IFileCategoryService
|
public class FileCategoryService : CrudCacheServiceBase<FileCategoryDto, FileCategory>, IFileCategoryService
|
||||||
{
|
{
|
||||||
public FileCategoryService(IAsbCloudDbContext context)
|
public FileCategoryService(IAsbCloudDbContext context, IMemoryCache memoryCache)
|
||||||
: base(context)
|
: base(context, memoryCache) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Перенести в сервис "дело скважины"
|
//TODO: Перенести в сервис "дело скважины"
|
||||||
public async Task<IEnumerable<FileCategoryDto>> GetWellCaseCategoriesAsync(CancellationToken token)
|
public async Task<IEnumerable<FileCategoryDto>> GetWellCaseCategoriesAsync(CancellationToken token)
|
||||||
|
@ -3,6 +3,7 @@ using AsbCloudApp.Services;
|
|||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Repository;
|
using AsbCloudInfrastructure.Repository;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -30,9 +31,9 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
private readonly SetpointsRequestRepository setpointsRepository;
|
private readonly SetpointsRequestRepository setpointsRepository;
|
||||||
private readonly ITelemetryService telemetryService;
|
private readonly ITelemetryService telemetryService;
|
||||||
|
|
||||||
public SetpointsService(IAsbCloudDbContext db, ITelemetryService telemetryService, IWellService wellService)
|
public SetpointsService(IAsbCloudDbContext db, IMemoryCache memoryCache, ITelemetryService telemetryService, IWellService wellService)
|
||||||
{
|
{
|
||||||
setpointsRepository = new SetpointsRequestRepository(db, wellService);
|
setpointsRepository = new SetpointsRequestRepository(db, memoryCache, wellService);
|
||||||
this.telemetryService = telemetryService;
|
this.telemetryService = telemetryService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb;
|
using AsbCloudDb;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -19,18 +18,15 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
{
|
{
|
||||||
protected readonly IAsbCloudDbContext db;
|
protected readonly IAsbCloudDbContext db;
|
||||||
private readonly ITelemetryService telemetryService;
|
private readonly ITelemetryService telemetryService;
|
||||||
protected readonly CacheTable<TelemetryUser> cacheTelemetryUsers;
|
|
||||||
private readonly TelemetryDataCache<TDto> telemetryDataCache;
|
private readonly TelemetryDataCache<TDto> telemetryDataCache;
|
||||||
|
|
||||||
public TelemetryDataBaseService(
|
public TelemetryDataBaseService(
|
||||||
IAsbCloudDbContext db,
|
IAsbCloudDbContext db,
|
||||||
ITelemetryService telemetryService,
|
ITelemetryService telemetryService,
|
||||||
TelemetryDataCache<TDto> telemetryDataCache,
|
TelemetryDataCache<TDto> telemetryDataCache)
|
||||||
CacheDb cacheDb)
|
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.telemetryService = telemetryService;
|
this.telemetryService = telemetryService;
|
||||||
cacheTelemetryUsers = cacheDb.GetCachedTable<TelemetryUser>((AsbCloudDbContext)db);
|
|
||||||
this.telemetryDataCache = telemetryDataCache;
|
this.telemetryDataCache = telemetryDataCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,32 +1,33 @@
|
|||||||
using AsbCloudApp.Data.SAUB;
|
using AsbCloudApp.Data.SAUB;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using DocumentFormat.OpenXml.Drawing.Charts;
|
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.SAUB
|
namespace AsbCloudInfrastructure.Services.SAUB
|
||||||
{
|
{
|
||||||
|
#nullable enable
|
||||||
public class TelemetryDataSaubService : TelemetryDataBaseService<TelemetryDataSaubDto, TelemetryDataSaub>
|
public class TelemetryDataSaubService : TelemetryDataBaseService<TelemetryDataSaubDto, TelemetryDataSaub>
|
||||||
{
|
{
|
||||||
|
private readonly ITelemetryUserService telemetryUserService;
|
||||||
|
|
||||||
public TelemetryDataSaubService(
|
public TelemetryDataSaubService(
|
||||||
IAsbCloudDbContext db,
|
IAsbCloudDbContext db,
|
||||||
ITelemetryService telemetryService,
|
ITelemetryService telemetryService,
|
||||||
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache,
|
ITelemetryUserService telemetryUserService,
|
||||||
CacheDb cacheDb)
|
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
|
||||||
: base(db, telemetryService, telemetryDataCache, cacheDb)
|
: base(db, telemetryService, telemetryDataCache)
|
||||||
{ }
|
{
|
||||||
|
this.telemetryUserService = telemetryUserService;
|
||||||
|
}
|
||||||
|
|
||||||
public override TelemetryDataSaub Convert(TelemetryDataSaubDto src, double timezoneOffset)
|
public override TelemetryDataSaub Convert(TelemetryDataSaubDto src, double timezoneOffset)
|
||||||
{
|
{
|
||||||
var entity = src.Adapt<TelemetryDataSaub>();
|
var entity = src.Adapt<TelemetryDataSaub>();
|
||||||
var telemetryUser = cacheTelemetryUsers?
|
var telemetryUser = telemetryUserService
|
||||||
.FirstOrDefault(u => u.IdTelemetry == src.IdTelemetry && (u.Name == src.User || u.Surname == src.User));
|
.GetUsers(src.IdTelemetry, u => (u.Name == src.User || u.Surname == src.User))
|
||||||
entity.IdUser = telemetryUser?.IdUser;
|
.FirstOrDefault();
|
||||||
|
entity.IdUser = telemetryUser?.Id;
|
||||||
entity.DateTime = src.DateTime.ToUtcDateTimeOffset(timezoneOffset);
|
entity.DateTime = src.DateTime.ToUtcDateTimeOffset(timezoneOffset);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
@ -34,11 +35,11 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
public override TelemetryDataSaubDto Convert(TelemetryDataSaub src, double timezoneOffset)
|
public override TelemetryDataSaubDto Convert(TelemetryDataSaub src, double timezoneOffset)
|
||||||
{
|
{
|
||||||
var dto = src.Adapt<TelemetryDataSaubDto>();
|
var dto = src.Adapt<TelemetryDataSaubDto>();
|
||||||
var telemetryUser = cacheTelemetryUsers?
|
var telemetryUser = telemetryUserService.GetOrDefault(src.IdTelemetry, src.IdUser??int.MinValue);
|
||||||
.FirstOrDefault(u => u.IdTelemetry == src.IdTelemetry && u.IdUser == src.IdUser);
|
|
||||||
dto.User = telemetryUser?.MakeDisplayName();
|
dto.User = telemetryUser?.MakeDisplayName();
|
||||||
dto.DateTime = src.DateTime.ToRemoteDateTime(timezoneOffset);
|
dto.DateTime = src.DateTime.ToRemoteDateTime(timezoneOffset);
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable disable
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
using AsbCloudApp.Data.SAUB;
|
using AsbCloudApp.Data.SAUB;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.SAUB
|
namespace AsbCloudInfrastructure.Services.SAUB
|
||||||
{
|
{
|
||||||
@ -13,9 +10,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
public TelemetryDataSpinService(
|
public TelemetryDataSpinService(
|
||||||
IAsbCloudDbContext db,
|
IAsbCloudDbContext db,
|
||||||
ITelemetryService telemetryService,
|
ITelemetryService telemetryService,
|
||||||
TelemetryDataCache<TelemetryDataSpinDto> telemetryDataCache,
|
TelemetryDataCache<TelemetryDataSpinDto> telemetryDataCache)
|
||||||
CacheDb cacheDb)
|
: base(db, telemetryService, telemetryDataCache)
|
||||||
: base(db, telemetryService, telemetryDataCache, cacheDb)
|
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public override TelemetryDataSpin Convert(TelemetryDataSpinDto src, double timezoneOffset)
|
public override TelemetryDataSpin Convert(TelemetryDataSpinDto src, double timezoneOffset)
|
||||||
|
@ -17,7 +17,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
public class TelemetryService : ITelemetryService
|
public class TelemetryService : ITelemetryService
|
||||||
{
|
{
|
||||||
private const string telemetryCacheTag = "telemetryCache";
|
private const string CacheTag = "TelemetryCache";
|
||||||
private static readonly TimeSpan telemetryCacheObsolescence = TimeSpan.FromMinutes(5);
|
private static readonly TimeSpan telemetryCacheObsolescence = TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
@ -39,15 +39,15 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
|
|
||||||
private IEnumerable<Telemetry> GetTelemetryCache()
|
private IEnumerable<Telemetry> GetTelemetryCache()
|
||||||
{
|
{
|
||||||
var cache = db.Telemetries
|
var cache = db.Set<Telemetry>()
|
||||||
.Include(t => t.Well)
|
.Include(t => t.Well)
|
||||||
.FromCache(telemetryCacheTag, telemetryCacheObsolescence);
|
.FromCache(CacheTag, telemetryCacheObsolescence);
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DropTelemetryCache()
|
private void DropTelemetryCache()
|
||||||
{
|
{
|
||||||
db.Telemetries.DropCache(telemetryCacheTag);
|
db.Telemetries.DropCache(CacheTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime GetLastTelemetryDate(int idTelemetry)
|
public DateTime GetLastTelemetryDate(int idTelemetry)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
@ -39,14 +39,14 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
|
|
||||||
private readonly ConcurrentDictionary<string, TrackerStat> telemetriesStats;
|
private readonly ConcurrentDictionary<string, TrackerStat> telemetriesStats;
|
||||||
|
|
||||||
public TelemetryTracker(CacheDb cacheDb, IConfiguration configuration)
|
public TelemetryTracker(IConfiguration configuration, IMemoryCache memoryCache)
|
||||||
{
|
{
|
||||||
var contextOptions = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
var contextOptions = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
||||||
.UseNpgsql(configuration.GetConnectionString("DefaultConnection"))
|
.UseNpgsql(configuration.GetConnectionString("DefaultConnection"))
|
||||||
.Options;
|
.Options;
|
||||||
var db = new AsbCloudDbContext(contextOptions);
|
var db = new AsbCloudDbContext(contextOptions);
|
||||||
|
|
||||||
var cacheTelemetry = cacheDb.GetCachedTable<Telemetry>(db);
|
var cacheTelemetry = memoryCache.GetOrCreateBasic<Telemetry>(db);
|
||||||
var keyValuePairs = new Dictionary<string, TrackerStat>(cacheTelemetry.Count());
|
var keyValuePairs = new Dictionary<string, TrackerStat>(cacheTelemetry.Count());
|
||||||
foreach (var telemetry in cacheTelemetry)
|
foreach (var telemetry in cacheTelemetry)
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,9 @@ using AsbCloudApp.Data.SAUB;
|
|||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb;
|
using AsbCloudDb;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.EfCache;
|
using Mapster;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -11,15 +13,49 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.SAUB
|
namespace AsbCloudInfrastructure.Services.SAUB
|
||||||
{
|
{
|
||||||
|
#nullable enable
|
||||||
public class TelemetryUserService : ITelemetryUserService
|
public class TelemetryUserService : ITelemetryUserService
|
||||||
{
|
{
|
||||||
|
private const string CacheTag = "TelemetryUserCacheTag";
|
||||||
|
private readonly TimeSpan CacheOlescence = TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
private readonly ITelemetryService telemetryService;
|
private readonly ITelemetryService telemetryService;
|
||||||
|
private readonly IMemoryCache memoryCache;
|
||||||
|
|
||||||
public TelemetryUserService(IAsbCloudDbContext db, ITelemetryService telemetryService)
|
public TelemetryUserService(IAsbCloudDbContext db,
|
||||||
|
ITelemetryService telemetryService,
|
||||||
|
IMemoryCache memoryCache)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.telemetryService = telemetryService;
|
this.telemetryService = telemetryService;
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TelemetryUserDto? GetOrDefault(int idTelemetry, int idUser)
|
||||||
|
{
|
||||||
|
var entity = GetCache()
|
||||||
|
.FirstOrDefault(u => u.IdTelemetry == idTelemetry && u.IdUser == idUser);
|
||||||
|
|
||||||
|
if(entity is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return Convert(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<TelemetryUserDto> GetUsers(int idTelemetry, Func<TelemetryUserDto, bool>? predicate = null)
|
||||||
|
{
|
||||||
|
var entities = GetCache()
|
||||||
|
.Where(u => u.IdTelemetry == idTelemetry);
|
||||||
|
|
||||||
|
foreach (var entity in entities)
|
||||||
|
{
|
||||||
|
var dto = Convert(entity);
|
||||||
|
if(predicate?.Invoke(dto)??true)
|
||||||
|
yield return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpsertAsync(string uid, IEnumerable<TelemetryUserDto> dtos, CancellationToken token = default)
|
public async Task UpsertAsync(string uid, IEnumerable<TelemetryUserDto> dtos, CancellationToken token = default)
|
||||||
@ -29,17 +65,37 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
|
|
||||||
var telemetryId = telemetryService.GetOrCreateTelemetryIdByUid(uid);
|
var telemetryId = telemetryService.GetOrCreateTelemetryIdByUid(uid);
|
||||||
|
|
||||||
var entities = dtos.Distinct(new TelemetryUserDtoComparer()).Select(dto => new TelemetryUser
|
var entities = dtos.Distinct(new TelemetryUserDtoComparer()).Select(dto => {
|
||||||
{
|
var entity = dto.Adapt<TelemetryUser>();
|
||||||
IdUser = dto.Id,
|
entity.IdUser = dto.Id;
|
||||||
IdTelemetry = telemetryId,
|
entity.IdTelemetry = telemetryId;
|
||||||
Level = dto.Level,
|
return entity;
|
||||||
Name = dto.Name,
|
|
||||||
Patronymic = dto.Patronymic,
|
|
||||||
Surname = dto.Surname,
|
|
||||||
});
|
});
|
||||||
var result = await db.Database.ExecInsertOrUpdateAsync(db.TelemetryUsers, entities, token);
|
var result = await db.Database.ExecInsertOrUpdateAsync(db.TelemetryUsers, entities, token);
|
||||||
db.TelemetryUsers.DropCache();
|
DropCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<TelemetryUser> GetCache()
|
||||||
|
{
|
||||||
|
var cache = memoryCache.GetOrCreate(CacheTag, cacheEntry => {
|
||||||
|
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
||||||
|
cacheEntry.SlidingExpiration = CacheOlescence;
|
||||||
|
|
||||||
|
var entities = db.Set<TelemetryUser>().ToArray();
|
||||||
|
return entities;
|
||||||
|
});
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DropCache()
|
||||||
|
=> memoryCache.Remove(CacheTag);
|
||||||
|
|
||||||
|
private static TelemetryUserDto Convert(TelemetryUser entity)
|
||||||
|
{
|
||||||
|
var dto = entity.Adapt<TelemetryUserDto>();
|
||||||
|
dto.Id = entity.IdUser;
|
||||||
|
return dto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable disable
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using AsbCloudDb.Model.Subsystems;
|
|||||||
using AsbCloudInfrastructure.Repository;
|
using AsbCloudInfrastructure.Repository;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -17,7 +18,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems
|
|||||||
internal class SubsystemService : CrudCacheServiceBase<SubsystemDto, Subsystem>, ISubsystemService
|
internal class SubsystemService : CrudCacheServiceBase<SubsystemDto, Subsystem>, ISubsystemService
|
||||||
{
|
{
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
public SubsystemService(IAsbCloudDbContext dbContext, IWellService wellService) : base(dbContext)
|
public SubsystemService(IAsbCloudDbContext dbContext, IMemoryCache memoryCache, IWellService wellService) : base(dbContext, memoryCache)
|
||||||
{
|
{
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
var result = new WellCaseDto
|
var result = new WellCaseDto
|
||||||
{
|
{
|
||||||
IdWell = idWell,
|
IdWell = idWell,
|
||||||
PermissionToSetPubliher = userRepository.HasPermission(idUser, "WellFinalDocument.editPublisher"),
|
PermissionToSetPubliher = userRepository.HasPermission(idUser, "WellFinalDocuments.editPublisher"),
|
||||||
WellFinalDocuments = docs,
|
WellFinalDocuments = docs,
|
||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -15,18 +15,14 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
public class OperationsStatService : IOperationsStatService
|
public class OperationsStatService : IOperationsStatService
|
||||||
{
|
{
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
|
private readonly IMemoryCache memoryCache;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly CacheTable<WellSectionType> cacheSectionsTypes;
|
|
||||||
private readonly CacheTable<WellType> cacheWellType;
|
|
||||||
private readonly CacheTable<Cluster> cacheCluster;
|
|
||||||
|
|
||||||
public OperationsStatService(IAsbCloudDbContext db, CacheDb cache, IWellService wellService)
|
public OperationsStatService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
cacheSectionsTypes = cache.GetCachedTable<WellSectionType>((DbContext)db);
|
|
||||||
cacheWellType = cache.GetCachedTable<WellType>((DbContext)db);
|
|
||||||
cacheCluster = cache.GetCachedTable<Cluster>((DbContext)db);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<StatClusterDto> GetStatClusterAsync(int idCluster, int idCompany, CancellationToken token = default)
|
public async Task<StatClusterDto> GetStatClusterAsync(int idCluster, int idCompany, CancellationToken token = default)
|
||||||
@ -44,7 +40,9 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
|
|
||||||
var statsWells = await GetWellsStatAsync(wells, token).ConfigureAwait(false);
|
var statsWells = await GetWellsStatAsync(wells, token).ConfigureAwait(false);
|
||||||
|
|
||||||
var cluster = await cacheCluster.FirstOrDefaultAsync(c => c.Id == idCluster, token);
|
var cluster = (await memoryCache
|
||||||
|
.GetOrCreateBasicAsync<Cluster>(db, token))
|
||||||
|
.FirstOrDefault(c => c.Id == idCluster);
|
||||||
var statClusterDto = new StatClusterDto
|
var statClusterDto = new StatClusterDto
|
||||||
{
|
{
|
||||||
Id = idCluster,
|
Id = idCluster,
|
||||||
@ -133,7 +131,9 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
|
|
||||||
private async Task<StatWellDto> CalcWellStatAsync(Well well, CancellationToken token = default)
|
private async Task<StatWellDto> CalcWellStatAsync(Well well, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
var wellType = await cacheWellType.FirstOrDefaultAsync(t => t.Id == well.IdWellType, token);
|
var wellType = (await memoryCache
|
||||||
|
.GetOrCreateBasicAsync<WellType>(db, token))
|
||||||
|
.FirstOrDefault(t => t.Id == well.IdWellType);
|
||||||
var statWellDto = new StatWellDto()
|
var statWellDto = new StatWellDto()
|
||||||
{
|
{
|
||||||
Id = well.Id,
|
Id = well.Id,
|
||||||
@ -169,7 +169,8 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
.Select(o => o.IdWellSectionType)
|
.Select(o => o.IdWellSectionType)
|
||||||
.Distinct();
|
.Distinct();
|
||||||
|
|
||||||
var sectionTypes = cacheSectionsTypes
|
var sectionTypes = memoryCache
|
||||||
|
.GetOrCreateBasic<WellSectionType>(db)
|
||||||
.Where(s => sectionTypeIds.Contains(s.Id))
|
.Where(s => sectionTypeIds.Contains(s.Id))
|
||||||
.ToDictionary(s => s.Id);
|
.ToDictionary(s => s.Id);
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -16,9 +16,8 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
public class WellOperationService : IWellOperationService
|
public class WellOperationService : IWellOperationService
|
||||||
{
|
{
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
|
private readonly IMemoryCache memoryCache;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly CacheTable<WellOperationCategory> cachedOperationCategories;
|
|
||||||
private readonly CacheTable<WellSectionType> cachedSectionTypes;
|
|
||||||
|
|
||||||
private Dictionary<int, DateTimeOffset?>? firstOperationsCache = null;
|
private Dictionary<int, DateTimeOffset?>? firstOperationsCache = null;
|
||||||
|
|
||||||
@ -33,22 +32,25 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
public const int idOperationTypeFact = 1;
|
public const int idOperationTypeFact = 1;
|
||||||
public const int idOperationTypeRepair = 1031;
|
public const int idOperationTypeRepair = 1031;
|
||||||
|
|
||||||
public WellOperationService(IAsbCloudDbContext db, CacheDb cache, IWellService wellService)
|
public WellOperationService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
cachedOperationCategories = cache.GetCachedTable<WellOperationCategory>((DbContext)db);
|
|
||||||
cachedSectionTypes = cache.GetCachedTable<WellSectionType>((DbContext)db);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDictionary<int, string> GetSectionTypes()
|
public IDictionary<int, string> GetSectionTypes()
|
||||||
=> cachedSectionTypes.ToDictionary(s => s.Id, s => s.Caption);
|
=> memoryCache
|
||||||
|
.GetOrCreateBasic<WellSectionType>(db)
|
||||||
|
.ToDictionary(s => s.Id, s => s.Caption);
|
||||||
|
|
||||||
public IEnumerable<WellOperationCategoryDto> GetCategories()
|
public IEnumerable<WellOperationCategoryDto> GetCategories()
|
||||||
{
|
{
|
||||||
var operationTypes = cachedOperationCategories
|
var operationCategories = memoryCache
|
||||||
.Distinct().OrderBy(o => o.Name);
|
.GetOrCreateBasic<WellOperationCategory>(db)
|
||||||
var result = operationTypes.Adapt<IEnumerable<WellOperationCategoryDto>>();
|
.Distinct()
|
||||||
|
.OrderBy(o => o.Name);
|
||||||
|
var result = operationCategories.Adapt<IEnumerable<WellOperationCategoryDto>>();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ using AsbCloudApp.Services;
|
|||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.EfCache;
|
using AsbCloudInfrastructure.EfCache;
|
||||||
using AsbCloudInfrastructure.Repository;
|
using AsbCloudInfrastructure.Repository;
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -36,14 +36,14 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
.Include(w => w.RelationCompaniesWells)
|
.Include(w => w.RelationCompaniesWells)
|
||||||
.ThenInclude(r => r.Company);
|
.ThenInclude(r => r.Company);
|
||||||
|
|
||||||
public WellService(IAsbCloudDbContext db, CacheDb cacheDb, ITelemetryService telemetryService, ITimezoneService timezoneService)
|
public WellService(IAsbCloudDbContext db, IMemoryCache memoryCache, ITelemetryService telemetryService, ITimezoneService timezoneService)
|
||||||
: base(db, MakeQueryWell)
|
: base(db, memoryCache, MakeQueryWell)
|
||||||
{
|
{
|
||||||
this.telemetryService = telemetryService;
|
this.telemetryService = telemetryService;
|
||||||
this.timezoneService = timezoneService;
|
this.timezoneService = timezoneService;
|
||||||
|
|
||||||
this.wellOperationService = new WellOperationService.WellOperationService(db, cacheDb, this);
|
this.wellOperationService = new WellOperationService.WellOperationService(db, memoryCache, this);
|
||||||
companyTypesService = new CrudCacheServiceBase<CompanyTypeDto, CompanyType>(dbContext);
|
companyTypesService = new CrudCacheServiceBase<CompanyTypeDto, CompanyType>(dbContext, memoryCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<RelationCompanyWell> GetCacheRelationCompanyWell()
|
private IEnumerable<RelationCompanyWell> GetCacheRelationCompanyWell()
|
||||||
@ -167,13 +167,6 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<CompanyDto> GetCompanies(int idWell)
|
|
||||||
{
|
|
||||||
var relations = GetCacheRelationCompanyWell().Where(r => r.IdWell == idWell);
|
|
||||||
var dtos = relations.Select(r => Convert(r.Company));
|
|
||||||
return dtos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetStateText(int state)
|
public string GetStateText(int state)
|
||||||
{
|
{
|
||||||
return state switch
|
return state switch
|
||||||
@ -339,7 +332,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
throw new Exception($"Well id: {idWell} does not exist.");
|
throw new Exception($"Well id: {idWell} does not exist.");
|
||||||
|
|
||||||
if (well.IdTelemetry is null)
|
if (well.IdTelemetry is null)
|
||||||
throw new Exception($"Well id: {idWell} does not contain telemetry.");
|
throw new KeyNotFoundException($"Well id: {idWell} does not contain telemetry.");
|
||||||
|
|
||||||
return telemetryService.GetDatesRange((int)well.IdTelemetry);
|
return telemetryService.GetDatesRange((int)well.IdTelemetry);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
protected override ICrudService<DepositDto> MakeService()
|
protected override ICrudService<DepositDto> MakeService()
|
||||||
{
|
{
|
||||||
var dbContext = TestHelpter.MakeRealTestContext();
|
var dbContext = TestHelpter.MakeRealTestContext();
|
||||||
return new CrudCacheServiceBase<DepositDto, Deposit>(dbContext);
|
return new CrudCacheServiceBase<DepositDto, Deposit>(dbContext, TestHelpter.MemoryCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,6 @@ using AsbCloudApp.Requests;
|
|||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Repository;
|
using AsbCloudInfrastructure.Repository;
|
||||||
using AsbCloudInfrastructure.Services;
|
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using AsbCloudInfrastructure.Services.DetectOperations;
|
using AsbCloudInfrastructure.Services.DetectOperations;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
@ -19,7 +17,6 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
public class DetectedOperationServiceTest
|
public class DetectedOperationServiceTest
|
||||||
{
|
{
|
||||||
private readonly AsbCloudDbContext context;
|
private readonly AsbCloudDbContext context;
|
||||||
private readonly CacheDb cacheDb;
|
|
||||||
private readonly DetectedOperationService service;
|
private readonly DetectedOperationService service;
|
||||||
private readonly DetectedOperationRequest request;
|
private readonly DetectedOperationRequest request;
|
||||||
private Deposit deposit = new Deposit { Id = 1, Caption = "Депозит 1" };
|
private Deposit deposit = new Deposit { Id = 1, Caption = "Депозит 1" };
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Repositories;
|
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
|
||||||
using AsbCloudInfrastructure.Repository;
|
|
||||||
using AsbCloudInfrastructure.Services;
|
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using AsbCloudApp.Data.SAUB;
|
using AsbCloudApp.Data.SAUB;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using AsbCloudInfrastructure.Services.SAUB;
|
using AsbCloudInfrastructure.Services.SAUB;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -14,13 +13,11 @@ namespace AsbCloudWebApi.Tests.ServicesTests;
|
|||||||
public class EventServiceTest
|
public class EventServiceTest
|
||||||
{
|
{
|
||||||
private readonly AsbCloudDbContext context;
|
private readonly AsbCloudDbContext context;
|
||||||
private readonly CacheDb cacheDb;
|
|
||||||
private readonly EventService service;
|
private readonly EventService service;
|
||||||
|
|
||||||
public EventServiceTest()
|
public EventServiceTest()
|
||||||
{
|
{
|
||||||
context = TestHelpter.MakeRealTestContext();
|
context = TestHelpter.MakeRealTestContext();
|
||||||
cacheDb = new CacheDb();
|
|
||||||
var telemetryTracker = new Mock<ITelemetryTracker>();
|
var telemetryTracker = new Mock<ITelemetryTracker>();
|
||||||
var imezoneServiceMock = new Mock<ITimezoneService>();
|
var imezoneServiceMock = new Mock<ITimezoneService>();
|
||||||
var telemetryService = new TelemetryService(context, telemetryTracker.Object, imezoneServiceMock.Object);
|
var telemetryService = new TelemetryService(context, telemetryTracker.Object, imezoneServiceMock.Object);
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudDb.Model;
|
|
||||||
using AsbCloudInfrastructure.Services;
|
using AsbCloudInfrastructure.Services;
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -19,7 +17,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
|
|
||||||
context = TestHelpter.MakeRealTestContext();
|
context = TestHelpter.MakeRealTestContext();
|
||||||
context.SaveChanges();
|
context.SaveChanges();
|
||||||
service = new FileCategoryService(context);
|
service = new FileCategoryService(context, TestHelpter.MemoryCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
~FileCategoryServiceTest()
|
~FileCategoryServiceTest()
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
using AsbCloudApp.Data.SAUB;
|
using AsbCloudApp.Data.SAUB;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using AsbCloudInfrastructure.Services.SAUB;
|
using AsbCloudInfrastructure.Services.SAUB;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
@ -20,9 +19,9 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
private readonly Mock<ITimezoneService> timezoneService;
|
private readonly Mock<ITimezoneService> timezoneService;
|
||||||
private readonly SimpleTimezoneDto timezone;
|
private readonly SimpleTimezoneDto timezone;
|
||||||
private readonly AsbCloudDbContext context;
|
private readonly AsbCloudDbContext context;
|
||||||
private readonly CacheDb cacheDb;
|
|
||||||
private readonly TelemetryService telemetryService;
|
private readonly TelemetryService telemetryService;
|
||||||
|
private readonly TelemetryUserService telemetryUserService;
|
||||||
|
private readonly TelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache;
|
||||||
private readonly DateTime drillingStartDate;
|
private readonly DateTime drillingStartDate;
|
||||||
private readonly string uuid;
|
private readonly string uuid;
|
||||||
public TelemetryDataSaubServiceTest()
|
public TelemetryDataSaubServiceTest()
|
||||||
@ -41,9 +40,9 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
.Returns(timezone);
|
.Returns(timezone);
|
||||||
|
|
||||||
context = TestHelpter.MakeRealTestContext();
|
context = TestHelpter.MakeRealTestContext();
|
||||||
cacheDb = new CacheDb();
|
|
||||||
telemetryService = new TelemetryService(context, telemetryTracker.Object, timezoneService.Object);
|
telemetryService = new TelemetryService(context, telemetryTracker.Object, timezoneService.Object);
|
||||||
|
telemetryUserService = new TelemetryUserService(context, telemetryService, TestHelpter.MemoryCache);
|
||||||
|
telemetryDataSaubCache = TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(context, out Task _);
|
||||||
var info = new TelemetryInfoDto
|
var info = new TelemetryInfoDto
|
||||||
{
|
{
|
||||||
TimeZoneOffsetTotalHours = timezone.Hours,
|
TimeZoneOffsetTotalHours = timezone.Hours,
|
||||||
@ -64,7 +63,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
public async Task UpdateDataAsync()
|
public async Task UpdateDataAsync()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var telemetryDataSaubService = new TelemetryDataSaubService(context, telemetryService, null, cacheDb);
|
var telemetryDataSaubService = new TelemetryDataSaubService(context, telemetryService, telemetryUserService, telemetryDataSaubCache);
|
||||||
|
|
||||||
var now = DateTimeOffset.UtcNow.ToOffset(TimeSpan.FromHours(timezone.Hours)).DateTime;
|
var now = DateTimeOffset.UtcNow.ToOffset(TimeSpan.FromHours(timezone.Hours)).DateTime;
|
||||||
var tuser = "Завулон";
|
var tuser = "Завулон";
|
||||||
|
@ -1,25 +1,27 @@
|
|||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.Tests
|
namespace AsbCloudWebApi.Tests
|
||||||
{
|
{
|
||||||
internal static class TestHelpter
|
internal static class TestHelpter
|
||||||
{
|
{
|
||||||
// Попробовать когда-нибудь https://github.com/MichalJankowskii/Moq.EntityFrameworkCore
|
public static IMemoryCache MemoryCache = new MemoryCache(new MemoryCacheOptions());
|
||||||
|
|
||||||
public static AsbCloudDbContext MakeRealTestContext()
|
public static AsbCloudDbContext MakeRealTestContext()
|
||||||
{
|
{
|
||||||
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
||||||
//.UseInMemoryDatabase(System.Guid.NewGuid().ToString())
|
|
||||||
//.ConfigureWarnings(configBuilder =>
|
|
||||||
// configBuilder.Ignore(InMemoryEventId.TransactionIgnoredWarning))
|
|
||||||
.UseNpgsql("Host=localhost;Database=tests;Username=postgres;Password=q;Persist Security Info=True;Include Error Detail=True")
|
.UseNpgsql("Host=localhost;Database=tests;Username=postgres;Password=q;Persist Security Info=True;Include Error Detail=True")
|
||||||
.Options;
|
.Options;
|
||||||
var context = new AsbCloudDbContext(options);
|
var context = new AsbCloudDbContext(options);
|
||||||
//context.Database.EnsureDeleted();
|
|
||||||
context.Database.EnsureCreated();
|
context.Database.EnsureCreated();
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
@ -31,22 +33,82 @@ namespace AsbCloudWebApi.Tests
|
|||||||
contextMock.Setup(o => o.Set<T>())
|
contextMock.Setup(o => o.Set<T>())
|
||||||
.Returns(() => dbSetMock.Object);
|
.Returns(() => dbSetMock.Object);
|
||||||
|
|
||||||
|
var dbSetProperty = typeof(IAsbCloudDbContext)
|
||||||
|
.GetProperties()
|
||||||
|
.FirstOrDefault(p => p.PropertyType.IsPublic && p.PropertyType == typeof(DbSet<T>));
|
||||||
|
|
||||||
|
if (dbSetProperty is not null)
|
||||||
|
{
|
||||||
|
// https://learn.microsoft.com/ru-ru/dotnet/api/system.linq.expressions.expression?view=net-7.0
|
||||||
|
var objParameterExpr = Expression.Parameter(typeof(IAsbCloudDbContext), "instance");
|
||||||
|
var propertyExpr = Expression.Property(objParameterExpr, dbSetProperty);
|
||||||
|
var expression = Expression.Lambda<Func<IAsbCloudDbContext, DbSet<T>>>(propertyExpr, objParameterExpr);
|
||||||
|
contextMock.SetupGet(expression).Returns(dbSetMock.Object);
|
||||||
|
}
|
||||||
|
|
||||||
return contextMock;
|
return contextMock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Mock<DbSet<T>> MakeDbSetMock<T>()
|
public static Mock<DbSet<T>> MakeDbSetMock<T>()
|
||||||
where T : class
|
where T : class
|
||||||
|
=> MakeDbSetMock(new List<T>());
|
||||||
|
|
||||||
|
class DummyAsyncQueriable<T> : IQueryable<T>, IAsyncEnumerable<T>
|
||||||
{
|
{
|
||||||
var dbSetData = new List<T>();
|
private readonly IQueryable<T> queriable;
|
||||||
return MakeDbSetMock(dbSetData);
|
|
||||||
|
public Type ElementType => queriable.ElementType;
|
||||||
|
|
||||||
|
public Expression Expression => queriable.Expression;
|
||||||
|
|
||||||
|
public IQueryProvider Provider => queriable.Provider;
|
||||||
|
|
||||||
|
class QueriableAsyncEminaretor<T2> : IAsyncEnumerator<T2>
|
||||||
|
{
|
||||||
|
private readonly IEnumerator<T2> syncEnumerator;
|
||||||
|
|
||||||
|
public QueriableAsyncEminaretor(IEnumerator<T2> syncEnumerator)
|
||||||
|
{
|
||||||
|
this.syncEnumerator = syncEnumerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T2 Current => syncEnumerator.Current;
|
||||||
|
|
||||||
|
public ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
syncEnumerator.Dispose();
|
||||||
|
return ValueTask.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueTask<bool> MoveNextAsync()
|
||||||
|
{
|
||||||
|
var result = syncEnumerator.MoveNext();
|
||||||
|
return ValueTask.FromResult(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DummyAsyncQueriable(IEnumerable<T> dbSetData)
|
||||||
|
{
|
||||||
|
queriable = dbSetData.ToList().AsQueryable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var enumerator = this.AsEnumerable().GetEnumerator();
|
||||||
|
return new QueriableAsyncEminaretor<T>(enumerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<T> GetEnumerator()
|
||||||
|
=> queriable.GetEnumerator();
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
=> queriable.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Mock<DbSet<T>> MakeDbSetMock<T>(IEnumerable<T> dbSetData)
|
public static Mock<DbSet<T>> MakeDbSetMock<T>(IEnumerable<T> dbSetData)
|
||||||
where T : class
|
where T : class
|
||||||
{
|
{
|
||||||
var dbSetDataQueriable = dbSetData
|
var dbSetDataQueriable = new DummyAsyncQueriable<T>(dbSetData);
|
||||||
.ToList()
|
|
||||||
.AsQueryable();
|
|
||||||
|
|
||||||
Mock<DbSet<T>> dbSetMock = new();
|
Mock<DbSet<T>> dbSetMock = new();
|
||||||
dbSetMock.As<IQueryable<T>>().Setup(o => o.Provider).Returns(() => dbSetDataQueriable.Provider);
|
dbSetMock.As<IQueryable<T>>().Setup(o => o.Provider).Returns(() => dbSetDataQueriable.Provider);
|
||||||
@ -54,6 +116,10 @@ namespace AsbCloudWebApi.Tests
|
|||||||
dbSetMock.As<IQueryable<T>>().Setup(o => o.ElementType).Returns(() => dbSetDataQueriable.ElementType);
|
dbSetMock.As<IQueryable<T>>().Setup(o => o.ElementType).Returns(() => dbSetDataQueriable.ElementType);
|
||||||
dbSetMock.As<IQueryable<T>>().Setup(o => o.GetEnumerator()).Returns(() => dbSetDataQueriable.GetEnumerator());
|
dbSetMock.As<IQueryable<T>>().Setup(o => o.GetEnumerator()).Returns(() => dbSetDataQueriable.GetEnumerator());
|
||||||
|
|
||||||
|
dbSetMock.As<IAsyncEnumerable<T>>()
|
||||||
|
.Setup(o => o.GetAsyncEnumerator(It.IsAny<CancellationToken>()))
|
||||||
|
.Returns(() => dbSetDataQueriable.GetAsyncEnumerator());
|
||||||
|
|
||||||
return dbSetMock;
|
return dbSetMock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data.SAUB;
|
||||||
using AsbCloudApp.Data.SAUB;
|
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudWebApi.SignalR;
|
using AsbCloudWebApi.SignalR;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -115,11 +115,15 @@ namespace AsbCloudWebApi.Controllers.SAUB
|
|||||||
|
|
||||||
if (!isCompanyOwnsWell)
|
if (!isCompanyOwnsWell)
|
||||||
return Forbid();
|
return Forbid();
|
||||||
|
try
|
||||||
|
{
|
||||||
var dataDatesRange = wellService.GetDatesRange(idWell);
|
var dataDatesRange = wellService.GetDatesRange(idWell);
|
||||||
|
|
||||||
return Ok(dataDatesRange);
|
return Ok(dataDatesRange);
|
||||||
}
|
}
|
||||||
|
catch(KeyNotFoundException)
|
||||||
|
{
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Services;
|
using AsbCloudInfrastructure.Services;
|
||||||
using AsbCloudInfrastructure.Services.Cache;
|
|
||||||
using AsbCloudInfrastructure.Services.SAUB;
|
using AsbCloudInfrastructure.Services.SAUB;
|
||||||
using AsbCloudInfrastructure.Services.WellOperationService;
|
using AsbCloudInfrastructure.Services.WellOperationService;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -41,19 +41,20 @@ namespace ConsoleApp1
|
|||||||
internal static class ServiceFactory
|
internal static class ServiceFactory
|
||||||
{
|
{
|
||||||
|
|
||||||
private static DbContextOptions<AsbCloudDbContext> options = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
private static readonly DbContextOptions<AsbCloudDbContext> options = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
||||||
.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True")
|
.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True")
|
||||||
.Options;
|
.Options;
|
||||||
|
|
||||||
static CacheDb CacheDb { get; } = new CacheDb();
|
|
||||||
static ConfigurationService ConfigurationService { get; } = new ConfigurationService();
|
static ConfigurationService ConfigurationService { get; } = new ConfigurationService();
|
||||||
static TimezoneService TimezoneService { get; } = new TimezoneService();
|
static TimezoneService TimezoneService { get; } = new TimezoneService();
|
||||||
public static AsbCloudDbContext Context { get; } = MakeContext();
|
public static AsbCloudDbContext Context { get; } = MakeContext();
|
||||||
public static AsbCloudDbContext MakeContext()
|
public static AsbCloudDbContext MakeContext()
|
||||||
=> MakeContext(options);
|
=> MakeContext(options);
|
||||||
|
|
||||||
|
public static IMemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions());
|
||||||
|
|
||||||
public static AsbCloudDbContext MakeContext(DbContextOptions<AsbCloudDbContext> options)
|
public static AsbCloudDbContext MakeContext(DbContextOptions<AsbCloudDbContext> options)
|
||||||
=> new AsbCloudDbContext(options);
|
=> new (options);
|
||||||
|
|
||||||
public static AsbCloudDbContext MakeContext(string cusomConnectionString)
|
public static AsbCloudDbContext MakeContext(string cusomConnectionString)
|
||||||
=> MakeContext(new DbContextOptionsBuilder<AsbCloudDbContext>().UseNpgsql(cusomConnectionString).Options);
|
=> MakeContext(new DbContextOptionsBuilder<AsbCloudDbContext>().UseNpgsql(cusomConnectionString).Options);
|
||||||
@ -62,21 +63,21 @@ namespace ConsoleApp1
|
|||||||
=> AsbCloudInfrastructure.DependencyInjection.MapsterSetup();
|
=> AsbCloudInfrastructure.DependencyInjection.MapsterSetup();
|
||||||
|
|
||||||
public static TelemetryTracker MakeTelemetryTracker()
|
public static TelemetryTracker MakeTelemetryTracker()
|
||||||
=> new TelemetryTracker(CacheDb, ConfigurationService);
|
=> new (ConfigurationService, memoryCache);
|
||||||
|
|
||||||
public static TelemetryService MakeTelemetryService()
|
public static TelemetryService MakeTelemetryService()
|
||||||
=> new TelemetryService(Context, MakeTelemetryTracker(), TimezoneService);
|
=> new (Context, MakeTelemetryTracker(), TimezoneService);
|
||||||
|
|
||||||
public static WellService MakeWellService()
|
public static WellService MakeWellService()
|
||||||
=> new WellService(Context, CacheDb, MakeTelemetryService(), TimezoneService);
|
=> new (Context, memoryCache, MakeTelemetryService(), TimezoneService);
|
||||||
|
|
||||||
public static WellOperationService MakeWellOperationsService()
|
public static WellOperationService MakeWellOperationsService()
|
||||||
=> new WellOperationService(Context, CacheDb, MakeWellService());
|
=> new (Context, memoryCache, MakeWellService());
|
||||||
|
|
||||||
public static OperationsStatService MakeOperationsStatService()
|
public static OperationsStatService MakeOperationsStatService()
|
||||||
=> new OperationsStatService(Context, CacheDb, MakeWellService());
|
=> new (Context, memoryCache, MakeWellService());
|
||||||
|
|
||||||
public static ScheduleReportService MakeScheduleReportService()
|
public static ScheduleReportService MakeScheduleReportService()
|
||||||
=> new ScheduleReportService(MakeOperationsStatService(), MakeWellService());
|
=> new(MakeOperationsStatService(), MakeWellService());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user