forked from ddrilling/AsbCloudServer
remove EfCacheExtensions, replace by IMemoryCache
This commit is contained in:
parent
f62b23fc47
commit
539d04d3cf
@ -1,421 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.EfCache
|
|
||||||
{
|
|
||||||
#nullable enable
|
|
||||||
/// <summary>
|
|
||||||
/// Кеширование запросов EF.<br/>
|
|
||||||
/// Кеш не отслеживается ChangeTracker.
|
|
||||||
/// </summary>
|
|
||||||
public static class EfCacheExtensions
|
|
||||||
{
|
|
||||||
private static readonly Dictionary<string, CacheItem> caches = new(16);
|
|
||||||
private static readonly TimeSpan semaphoreTimeout = TimeSpan.FromSeconds(25);
|
|
||||||
private static readonly SemaphoreSlim semaphore = new(1);
|
|
||||||
private static readonly TimeSpan minCacheTime = TimeSpan.FromSeconds(2);
|
|
||||||
private static readonly TimeSpan defaultObsolescence = TimeSpan.FromMinutes(4);
|
|
||||||
|
|
||||||
private class YieldConvertedData<TEntity, TModel> : IEnumerable<TModel>
|
|
||||||
{
|
|
||||||
private struct ConvertedData
|
|
||||||
{
|
|
||||||
public TEntity? Entity;
|
|
||||||
public TModel? Model;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConvertedData[] data;
|
|
||||||
public Func<TEntity, TModel> convert { get; }
|
|
||||||
|
|
||||||
public YieldConvertedData(TEntity[] entities, Func<TEntity, TModel> convert)
|
|
||||||
{
|
|
||||||
data = (entities.Select(x => new ConvertedData {
|
|
||||||
Entity = x,
|
|
||||||
Model = default }))
|
|
||||||
.ToArray();
|
|
||||||
this.convert = convert;
|
|
||||||
}
|
|
||||||
|
|
||||||
class YieldConvertedDataEnumerator : IEnumerator<TModel>
|
|
||||||
{
|
|
||||||
private readonly ConvertedData[] data;
|
|
||||||
private readonly Func<TEntity, TModel> convert;
|
|
||||||
private int position = -1;
|
|
||||||
|
|
||||||
public YieldConvertedDataEnumerator(ConvertedData[] data, Func<TEntity, TModel> convert)
|
|
||||||
{
|
|
||||||
this.data = data;
|
|
||||||
this.convert = convert;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TModel Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (data[position].Entity is TEntity entity)
|
|
||||||
{
|
|
||||||
var dto = convert(entity);
|
|
||||||
data[position].Entity = default;
|
|
||||||
data[position].Model = dto;
|
|
||||||
}
|
|
||||||
return data[position].Model!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object IEnumerator.Current => Current!;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
position++;
|
|
||||||
return (position < data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
position = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<TModel> GetEnumerator()
|
|
||||||
{
|
|
||||||
var result = new YieldConvertedDataEnumerator(data, convert);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class CacheItem
|
|
||||||
{
|
|
||||||
internal IEnumerable? Data;
|
|
||||||
internal DateTime DateObsolete;
|
|
||||||
internal DateTime DateObsoleteTotal;
|
|
||||||
internal readonly SemaphoreSlim semaphore = new(1);
|
|
||||||
|
|
||||||
internal IEnumerable<TEntity> GetData<TEntity>()
|
|
||||||
{
|
|
||||||
if (Data is IEnumerable<TEntity> typedData)
|
|
||||||
return typedData;
|
|
||||||
throw new TypeAccessException("Cache data has wrong type. Possible 'tag' is not unique.");
|
|
||||||
}
|
|
||||||
|
|
||||||
internal IEnumerable<TModel> GetData<TEntity, TModel>(Func<TEntity, TModel> convert, int attempt = 1)
|
|
||||||
{
|
|
||||||
if (Data is IEnumerable<TModel> typedData)
|
|
||||||
return typedData;
|
|
||||||
if (Data is IEnumerable<TEntity> typedEntityData)
|
|
||||||
{
|
|
||||||
if (semaphore.Wait(0))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var convertedData = new YieldConvertedData<TEntity, TModel>(typedEntityData.ToArray(), convert);
|
|
||||||
Data = convertedData;
|
|
||||||
return convertedData;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (semaphore.Wait(semaphoreTimeout))
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
throw new TimeoutException("EfCacheL2.GetData. Can't wait too long while converting cache data");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (attempt > 0)
|
|
||||||
return GetData(convert, --attempt);
|
|
||||||
throw new TypeAccessException("Cache data has wrong type. Possible 'tag' is not unique.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CacheItem GetOrAddCache(string tag, Func<object[]> valueFactory, TimeSpan obsolete)
|
|
||||||
{
|
|
||||||
CacheItem cache;
|
|
||||||
while (!caches.ContainsKey(tag))
|
|
||||||
{
|
|
||||||
if (semaphore.Wait(0))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!caches.ContainsKey(tag))
|
|
||||||
{
|
|
||||||
cache = new CacheItem();
|
|
||||||
caches.Add(tag, cache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (semaphore.Wait(semaphoreTimeout))
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
throw new TimeoutException("EfCacheL2.GetOrAddCache. Can't wait too long while getting cache");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cache = caches[tag];
|
|
||||||
|
|
||||||
if (cache.DateObsolete < DateTime.Now)
|
|
||||||
{
|
|
||||||
if (cache.semaphore.Wait(0))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var dateObsolete = DateTime.Now + obsolete;
|
|
||||||
var dateQueryStart = DateTime.Now;
|
|
||||||
var data = valueFactory();
|
|
||||||
var queryTime = DateTime.Now - dateQueryStart;
|
|
||||||
|
|
||||||
if (dateObsolete - DateTime.Now < minCacheTime)
|
|
||||||
dateObsolete = DateTime.Now + minCacheTime;
|
|
||||||
|
|
||||||
cache.Data = data;
|
|
||||||
cache.DateObsolete = dateObsolete;
|
|
||||||
cache.DateObsoleteTotal = dateObsolete + queryTime + minCacheTime;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
cache.semaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cache.DateObsoleteTotal < DateTime.Now)
|
|
||||||
{
|
|
||||||
if (cache.semaphore.Wait(semaphoreTimeout))
|
|
||||||
{
|
|
||||||
cache.semaphore.Release();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cache.semaphore.Release();
|
|
||||||
throw new TimeoutException("EfCacheL2.GetOrAddCache. Can't wait too long while getting cache");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<CacheItem> GetOrAddCacheAsync(string tag, Func<CancellationToken, Task<object[]>> valueFactoryAsync, TimeSpan obsolete, CancellationToken token)
|
|
||||||
{
|
|
||||||
CacheItem cache;
|
|
||||||
while (!caches.ContainsKey(tag))
|
|
||||||
{
|
|
||||||
if (semaphore.Wait(0))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!caches.ContainsKey(tag))
|
|
||||||
{
|
|
||||||
cache = new CacheItem();
|
|
||||||
caches.Add(tag, cache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (await semaphore.WaitAsync(semaphoreTimeout, token))
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
throw new TimeoutException("EfCacheL2.GetOrAddCache. Can't wait too long while getting cache");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cache = caches[tag];
|
|
||||||
|
|
||||||
if (cache.DateObsolete < DateTime.Now)
|
|
||||||
{
|
|
||||||
if (cache.semaphore.Wait(0))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var dateObsolete = DateTime.Now + obsolete;
|
|
||||||
var dateQueryStart = DateTime.Now;
|
|
||||||
var data = await valueFactoryAsync(token);
|
|
||||||
var queryTime = DateTime.Now - dateQueryStart;
|
|
||||||
|
|
||||||
if (dateObsolete - DateTime.Now < minCacheTime)
|
|
||||||
dateObsolete = DateTime.Now + minCacheTime;
|
|
||||||
|
|
||||||
cache.Data = data;
|
|
||||||
cache.DateObsolete = dateObsolete;
|
|
||||||
cache.DateObsoleteTotal = dateObsolete + queryTime + minCacheTime;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
cache.semaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cache.DateObsoleteTotal < DateTime.Now)
|
|
||||||
{
|
|
||||||
if (await cache.semaphore.WaitAsync(semaphoreTimeout, token))
|
|
||||||
{
|
|
||||||
cache.semaphore.Release();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cache.semaphore.Release();
|
|
||||||
throw new TimeoutException("EfCacheL2.GetOrAddCache. Can't wait too long while getting updated cache");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Кешировать запрос в List<<typeparamref name="TEntity"/>>. Кеш tag = typeof(TEntity).Name
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TEntity"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static IEnumerable<TEntity> FromCache<TEntity>(this IQueryable<TEntity> query)
|
|
||||||
where TEntity : class
|
|
||||||
{
|
|
||||||
var tag = typeof(TEntity).Name;
|
|
||||||
return FromCache(query, tag, defaultObsolescence);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Кешировать запрос в List<<typeparamref name="TEntity"/>>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TEntity"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="tag">Метка кеша</param>
|
|
||||||
/// <param name="obsolescence">Период устаревания данных</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static IEnumerable<TEntity> FromCache<TEntity>(this IQueryable<TEntity> query, string tag, TimeSpan obsolescence)
|
|
||||||
where TEntity : class
|
|
||||||
{
|
|
||||||
object[] factory() => query.AsNoTracking().ToArray();
|
|
||||||
var cache = GetOrAddCache(tag, factory, obsolescence);
|
|
||||||
return cache.GetData<TEntity>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Кешировать запрос с последующим преобразованием из <typeparamref name="TEntity"/> в <typeparamref name="TModel"/>.<br/>
|
|
||||||
/// Преобразование выполняется после получения из БД, результат кешируется в List<<typeparamref name="TEntity"/>>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TEntity"></typeparam>
|
|
||||||
/// <typeparam name="TModel"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="tag">Метка кеша</param>
|
|
||||||
/// <param name="obsolescence">Период устаревания данных</param>
|
|
||||||
/// <param name="convert">Преобразование данных БД в DTO</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static IEnumerable<TModel> FromCache<TEntity, TModel>(this IQueryable<TEntity> query, string tag, TimeSpan obsolescence, Func<TEntity, TModel> convert)
|
|
||||||
where TEntity : class
|
|
||||||
{
|
|
||||||
object[] factory() => query.AsNoTracking().ToArray();
|
|
||||||
var cache = GetOrAddCache(tag, factory, obsolescence);
|
|
||||||
return cache.GetData(convert);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Task<IEnumerable<TEntity>> FromCacheAsync<TEntity>(this IQueryable<TEntity> query, CancellationToken token)
|
|
||||||
where TEntity : class
|
|
||||||
{
|
|
||||||
var tag = typeof(TEntity).Name;
|
|
||||||
return FromCacheAsync(query, tag, defaultObsolescence, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Асинхронно кешировать запрос в List<<typeparamref name="TEntity"/>>.<br/>
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TEntity"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="tag">Метка кеша</param>
|
|
||||||
/// <param name="obsolescence">Период устаревания данных</param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<IEnumerable<TEntity>> FromCacheAsync<TEntity>(this IQueryable<TEntity> query, string tag, TimeSpan obsolescence, CancellationToken token)
|
|
||||||
where TEntity : class
|
|
||||||
{
|
|
||||||
async Task<object[]> factory(CancellationToken token)
|
|
||||||
=> await query.AsNoTracking().ToArrayAsync(token);
|
|
||||||
var cache = await GetOrAddCacheAsync(tag, factory, obsolescence, token);
|
|
||||||
return cache.GetData<TEntity>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Асинхронно кешировать запрос с последующим преобразованием из <typeparamref name="TEntity"/> в <typeparamref name="TModel"/>.<br/>
|
|
||||||
/// Преобразование выполняется после получения из БД, результат кешируется в List<<typeparamref name="TModel"/>>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TEntity"></typeparam>
|
|
||||||
/// <typeparam name="TModel"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="tag">Метка кеша</param>
|
|
||||||
/// <param name="obsolescence">Период устаревания данных</param>
|
|
||||||
/// <param name="convert">Преобразование данных БД в DTO</param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<IEnumerable<TModel>> FromCacheAsync<TEntity, TModel>(this IQueryable<TEntity> query, string tag, TimeSpan obsolescence, Func<TEntity, TModel> convert, CancellationToken token)
|
|
||||||
where TEntity : class
|
|
||||||
{
|
|
||||||
async Task<object[]> factory(CancellationToken token)
|
|
||||||
=> await query.AsNoTracking().ToArrayAsync(token);
|
|
||||||
var cache = await GetOrAddCacheAsync(tag, factory, obsolescence, token);
|
|
||||||
return cache.GetData(convert);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// drops cache with tag = typeof(T).Name
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
public static void DropCache<T>(this IQueryable<T> query)
|
|
||||||
{
|
|
||||||
var tag = typeof(T).Name;
|
|
||||||
DropCache(query, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Очистить кеш
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="tag">Метка кеша</param>
|
|
||||||
public static void DropCache<T>(this IQueryable<T> query, string tag)
|
|
||||||
{
|
|
||||||
caches.Remove(tag, out var _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#nullable disable
|
|
||||||
}
|
|
@ -9,36 +9,121 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace AsbCloudInfrastructure
|
namespace AsbCloudInfrastructure
|
||||||
{
|
{
|
||||||
|
#nullable enable
|
||||||
public static class MemoryCacheExtentions
|
public static class MemoryCacheExtentions
|
||||||
{
|
{
|
||||||
private static readonly TimeSpan CacheOlescence = TimeSpan.FromMinutes(5);
|
private static readonly TimeSpan CacheOlescence = TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Создать кеш на основе асинхронного запроса к БД.
|
||||||
|
/// Ключ кеша - полное имя типа T.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="memoryCache"></param>
|
||||||
|
/// <param name="query"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Task<IEnumerable<T>> GetOrCreateBasicAsync<T>(this IMemoryCache memoryCache, IQueryable<T> query, CancellationToken token)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
var getter = async (CancellationToken token) =>
|
||||||
|
{
|
||||||
|
var entities = await query
|
||||||
|
.ToArrayAsync(token);
|
||||||
|
return entities.AsEnumerable();
|
||||||
|
};
|
||||||
|
return memoryCache.GetOrCreateBasicAsync(getter, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete(message: "use GetOrCreateBasicAsync<T>(this IMemoryCache memoryCache, IQueryable<T> query, CancellationToken token)")]
|
||||||
public static Task<IEnumerable<T>> GetOrCreateBasicAsync<T>(this IMemoryCache memoryCache, IAsbCloudDbContext dbContext, CancellationToken token)
|
public static Task<IEnumerable<T>> GetOrCreateBasicAsync<T>(this IMemoryCache memoryCache, IAsbCloudDbContext dbContext, CancellationToken token)
|
||||||
where T : class
|
where T : class
|
||||||
{
|
{
|
||||||
var cacheTag = typeof(T).FullName;
|
var getter = async (CancellationToken token) =>
|
||||||
var cache = memoryCache.GetOrCreateAsync(cacheTag, async (cacheEntry) => {
|
{
|
||||||
|
var entities = await dbContext.Set<T>()
|
||||||
|
.ToArrayAsync(token);
|
||||||
|
return entities.AsEnumerable();
|
||||||
|
};
|
||||||
|
return memoryCache.GetOrCreateBasicAsync(getter, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Создать кеш на основе результата выполнения произвольной асинхронной функции.
|
||||||
|
/// Ключ кеша - полное имя типа T.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="memoryCache"></param>
|
||||||
|
/// <param name="getterAsync"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Task<IEnumerable<T>> GetOrCreateBasicAsync<T>(this IMemoryCache memoryCache, Func<CancellationToken, Task<IEnumerable<T>>> getterAsync, CancellationToken token)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
var key = typeof(T).FullName;
|
||||||
|
var cache = memoryCache.GetOrCreateAsync(key, async (cacheEntry) => {
|
||||||
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
||||||
cacheEntry.SlidingExpiration = CacheOlescence;
|
cacheEntry.SlidingExpiration = CacheOlescence;
|
||||||
|
var entities = await getterAsync(token);
|
||||||
var entities = await dbContext.Set<T>().ToArrayAsync(token);
|
return entities;
|
||||||
return entities.AsEnumerable();
|
|
||||||
});
|
});
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Создать кеш на основе запроса к БД.
|
||||||
|
/// Ключ кеша - полное имя типа T.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="memoryCache"></param>
|
||||||
|
/// <param name="query"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IEnumerable<T> GetOrCreateBasic<T>(this IMemoryCache memoryCache, IQueryable<T> query)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
var getter = () => query.ToArray();
|
||||||
|
return memoryCache.GetOrCreateBasic(getter);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete(message: "use GetOrCreateBasic<T>(this IMemoryCache memoryCache, IQueryable<T> query)")]
|
||||||
public static IEnumerable<T> GetOrCreateBasic<T>(this IMemoryCache memoryCache, IAsbCloudDbContext dbContext)
|
public static IEnumerable<T> GetOrCreateBasic<T>(this IMemoryCache memoryCache, IAsbCloudDbContext dbContext)
|
||||||
where T : class
|
where T : class
|
||||||
{
|
{
|
||||||
var cacheTag = typeof(T).FullName;
|
var getter = () => dbContext.Set<T>().ToArray();
|
||||||
var cache = memoryCache.GetOrCreate(cacheTag, cacheEntry => {
|
return memoryCache.GetOrCreateBasic(getter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Создать кеш на основе результата выполнения произвольной функции.
|
||||||
|
/// Ключ кеша - полное имя типа T.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="memoryCache"></param>
|
||||||
|
/// <param name="getter"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IEnumerable<T> GetOrCreateBasic<T>(this IMemoryCache memoryCache, Func<IEnumerable<T>> getter)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
var key = typeof(T).FullName;
|
||||||
|
var cache = memoryCache.GetOrCreate(key, cacheEntry => {
|
||||||
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
||||||
cacheEntry.SlidingExpiration = CacheOlescence;
|
cacheEntry.SlidingExpiration = CacheOlescence;
|
||||||
|
return getter();
|
||||||
var entities = dbContext.Set<T>().ToArray();
|
|
||||||
return entities.AsEnumerable();
|
|
||||||
});
|
});
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сбросить кеш.
|
||||||
|
/// Ключ кеша - полное имя типа T.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="memoryCache"></param>
|
||||||
|
public static void DropBasic<T>(this IMemoryCache memoryCache)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
var key = typeof(T).FullName;
|
||||||
|
memoryCache.Remove(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ using AsbCloudApp.Exceptions;
|
|||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudDb;
|
using AsbCloudDb;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.EfCache;
|
|
||||||
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;
|
||||||
@ -19,14 +19,12 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
public class UserRoleRepository : IUserRoleRepository
|
public class UserRoleRepository : IUserRoleRepository
|
||||||
{
|
{
|
||||||
private readonly IAsbCloudDbContext dbContext;
|
private readonly IAsbCloudDbContext dbContext;
|
||||||
private const string userRoleCacheTag = "UserRole";
|
private readonly IMemoryCache memoryCache;
|
||||||
private const string relationUserRoleUserRoleCacheTag = "RelationUserRoleUserRole";
|
|
||||||
private const string relationUserRolePermissionsCacheTag = "RelationUserRolePermissions";
|
|
||||||
private static readonly TimeSpan relationCacheObsolence = TimeSpan.FromMinutes(15);
|
|
||||||
|
|
||||||
public UserRoleRepository(IAsbCloudDbContext dbContext)
|
public UserRoleRepository(IAsbCloudDbContext dbContext, IMemoryCache memoryCache)
|
||||||
{
|
{
|
||||||
this.dbContext = dbContext;
|
this.dbContext = dbContext;
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> InsertAsync(UserRoleDto dto, CancellationToken token)
|
public async Task<int> InsertAsync(UserRoleDto dto, CancellationToken token)
|
||||||
@ -239,30 +237,30 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Task<IEnumerable<UserRole>> GetCacheUserRoleAsync(CancellationToken token)
|
private Task<IEnumerable<UserRole>> GetCacheUserRoleAsync(CancellationToken token)
|
||||||
=> dbContext.UserRoles
|
=> memoryCache.GetOrCreateBasicAsync(dbContext.Set<UserRole>()
|
||||||
.Include(r => r.RelationUserRolePermissions)
|
.Include(r => r.RelationUserRolePermissions)
|
||||||
.Include(r => r.RelationUserRoleUserRoles)
|
.Include(r => r.RelationUserRoleUserRoles)
|
||||||
.Include(r => r.RelationUsersUserRoles)
|
.Include(r => r.RelationUsersUserRoles), token);
|
||||||
.FromCacheAsync(userRoleCacheTag, relationCacheObsolence, token);
|
|
||||||
private IEnumerable<UserRole> GetCacheUserRole()
|
private IEnumerable<UserRole> GetCacheUserRole()
|
||||||
=> dbContext.UserRoles
|
=> memoryCache.GetOrCreateBasic(dbContext.Set<UserRole>()
|
||||||
.Include(r => r.RelationUserRolePermissions)
|
.Include(r => r.RelationUserRolePermissions)
|
||||||
.Include(r => r.RelationUserRoleUserRoles)
|
.Include(r => r.RelationUserRoleUserRoles)
|
||||||
.Include(r => r.RelationUsersUserRoles)
|
.Include(r => r.RelationUsersUserRoles));
|
||||||
.FromCache(userRoleCacheTag, relationCacheObsolence);
|
|
||||||
private void DropCacheUserRole()
|
private void DropCacheUserRole()
|
||||||
=> dbContext.RelationUserUserRoles.DropCache(userRoleCacheTag);
|
=> memoryCache.DropBasic<UserRole>();
|
||||||
|
|
||||||
private void DropCacheRelationUserRoleUserRole()
|
private void DropCacheRelationUserRoleUserRole()
|
||||||
=> dbContext.RelationUserUserRoles.DropCache(relationUserRoleUserRoleCacheTag);
|
=> memoryCache.DropBasic<RelationUserUserRole>();
|
||||||
|
|
||||||
private IEnumerable<RelationUserRolePermission> GetCacheRelationUserRolePermissions()
|
private IEnumerable<RelationUserRolePermission> GetCacheRelationUserRolePermissions()
|
||||||
=> dbContext.RelationUserRolePermissions
|
=> memoryCache.GetOrCreateBasic(dbContext.Set<RelationUserRolePermission>()
|
||||||
.Include(r => r.UserRole)
|
.Include(r => r.UserRole)
|
||||||
.Include(r => r.Permission)
|
.Include(r => r.Permission));
|
||||||
.FromCache(relationUserRolePermissionsCacheTag, relationCacheObsolence);
|
|
||||||
private void DropCacheRelationUserRolePermissions()
|
private void DropCacheRelationUserRolePermissions()
|
||||||
=> dbContext.RelationUserRolePermissions.DropCache(relationUserRolePermissionsCacheTag);
|
=> memoryCache.DropBasic<RelationUserRolePermission>();
|
||||||
|
|
||||||
private UserRoleDto Convert(UserRole entity)
|
private UserRoleDto Convert(UserRole entity)
|
||||||
{
|
{
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
using AsbCloudApp.Exceptions;
|
using AsbCloudApp.Exceptions;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.EfCache;
|
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
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;
|
||||||
@ -15,20 +16,28 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
public class MeasureService : IMeasureService
|
public class MeasureService : IMeasureService
|
||||||
{
|
{
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
|
private readonly IMemoryCache memoryCache;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private static readonly System.TimeSpan cacheObsolescence = System.TimeSpan.FromMinutes(15);
|
private static readonly TimeSpan CacheOlescence = TimeSpan.FromMinutes(20);
|
||||||
|
|
||||||
public MeasureService(IAsbCloudDbContext db, IWellService wellService)
|
public MeasureService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Dictionary<int, string>> GetCategoriesAsync(CancellationToken token)
|
public async Task<Dictionary<int, string>> GetCategoriesAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
var entities = await db.MeasureCategories.FromCacheAsync("MeasureCategories", cacheObsolescence, token).ConfigureAwait(false);
|
var key = typeof(MeasureCategory).FullName;
|
||||||
var dto = entities.ToDictionary(e => e.Id, e => e.Name);
|
var cache = await memoryCache.GetOrCreateAsync(key, async (cacheEntry) => {
|
||||||
return dto;
|
cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence;
|
||||||
|
cacheEntry.SlidingExpiration = CacheOlescence;
|
||||||
|
var entities = await db.Set<MeasureCategory>()
|
||||||
|
.ToDictionaryAsync(e => e.Id, e => e.Name, token);
|
||||||
|
return entities;
|
||||||
|
});
|
||||||
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<MeasureDto> GetLastAsync(int idWell, int idCategory, CancellationToken token)
|
public async Task<MeasureDto> GetLastAsync(int idWell, int idCategory, CancellationToken token)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb;
|
using AsbCloudDb;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.EfCache;
|
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;
|
||||||
@ -13,11 +13,13 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
public class EventService : IEventService
|
public class EventService : IEventService
|
||||||
{
|
{
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
|
private readonly IMemoryCache memoryCache;
|
||||||
private readonly ITelemetryService telemetryService;
|
private readonly ITelemetryService telemetryService;
|
||||||
|
|
||||||
public EventService(IAsbCloudDbContext db, ITelemetryService telemetryService)
|
public EventService(IAsbCloudDbContext db, IMemoryCache memoryCache, ITelemetryService telemetryService)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
this.telemetryService = telemetryService;
|
this.telemetryService = telemetryService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +39,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
MessageTemplate = dto.Message
|
MessageTemplate = dto.Message
|
||||||
});
|
});
|
||||||
var result = await db.Database.ExecInsertOrUpdateAsync(db.TelemetryEvents, entities, token);
|
var result = await db.Database.ExecInsertOrUpdateAsync(db.TelemetryEvents, entities, token);
|
||||||
db.TelemetryEvents.DropCache();
|
memoryCache.DropBasic<TelemetryEvent>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ using AsbCloudApp.Requests;
|
|||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb;
|
using AsbCloudDb;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.EfCache;
|
|
||||||
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;
|
||||||
@ -19,11 +19,13 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
public class MessageService : IMessageService
|
public class MessageService : IMessageService
|
||||||
{
|
{
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
|
private readonly IMemoryCache memoryCache;
|
||||||
private readonly ITelemetryService telemetryService;
|
private readonly ITelemetryService telemetryService;
|
||||||
|
|
||||||
public MessageService(IAsbCloudDbContext db, ITelemetryService telemetryService)
|
public MessageService(IAsbCloudDbContext db, IMemoryCache memoryCache, ITelemetryService telemetryService)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
this.telemetryService = telemetryService;
|
this.telemetryService = telemetryService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +41,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
if (idTelemetry is null)
|
if (idTelemetry is null)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
var allEvents = await db.TelemetryEvents.FromCacheAsync(token);
|
var allEvents = await memoryCache.GetOrCreateBasicAsync(db.Set<TelemetryEvent>(), token);
|
||||||
var events = allEvents.Where(e => e.IdTelemetry == idTelemetry);
|
var events = allEvents.Where(e => e.IdTelemetry == idTelemetry);
|
||||||
|
|
||||||
if (!events.Any())
|
if (!events.Any())
|
||||||
@ -93,7 +95,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
if (messagesList.Count == 0)
|
if (messagesList.Count == 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
var allUsers = await db.TelemetryUsers.FromCacheAsync(token);
|
var allUsers = await memoryCache.GetOrCreateBasicAsync(db.Set<TelemetryUser>(), token);
|
||||||
var users = allUsers.Where(u => u.IdTelemetry == idTelemetry);
|
var users = allUsers.Where(u => u.IdTelemetry == idTelemetry);
|
||||||
|
|
||||||
var eventsDict = events.ToDictionary(x=>x.IdEvent, x => x);
|
var eventsDict = events.ToDictionary(x=>x.IdEvent, x => x);
|
||||||
|
@ -3,9 +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 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;
|
||||||
@ -17,10 +17,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
public class TelemetryService : ITelemetryService
|
public class TelemetryService : ITelemetryService
|
||||||
{
|
{
|
||||||
private const string CacheTag = "TelemetryCache";
|
|
||||||
private static readonly TimeSpan telemetryCacheObsolescence = TimeSpan.FromMinutes(5);
|
|
||||||
|
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
|
private readonly IMemoryCache memoryCache;
|
||||||
private readonly ITelemetryTracker telemetryTracker;
|
private readonly ITelemetryTracker telemetryTracker;
|
||||||
private readonly ITimezoneService timezoneService;
|
private readonly ITimezoneService timezoneService;
|
||||||
|
|
||||||
@ -29,25 +27,27 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
|
|
||||||
public TelemetryService(
|
public TelemetryService(
|
||||||
IAsbCloudDbContext db,
|
IAsbCloudDbContext db,
|
||||||
|
IMemoryCache memoryCache,
|
||||||
ITelemetryTracker telemetryTracker,
|
ITelemetryTracker telemetryTracker,
|
||||||
ITimezoneService timezoneService)
|
ITimezoneService timezoneService)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
this.telemetryTracker = telemetryTracker;
|
this.telemetryTracker = telemetryTracker;
|
||||||
this.timezoneService = timezoneService;
|
this.timezoneService = timezoneService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<Telemetry> GetTelemetryCache()
|
private IEnumerable<Telemetry> GetTelemetryCache()
|
||||||
{
|
{
|
||||||
var cache = db.Set<Telemetry>()
|
var getter = () => db.Set<Telemetry>()
|
||||||
.Include(t => t.Well)
|
.Include(t => t.Well)
|
||||||
.FromCache(CacheTag, telemetryCacheObsolescence);
|
.ToArray();
|
||||||
return cache;
|
return memoryCache.GetOrCreateBasic(getter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DropTelemetryCache()
|
private void DropTelemetryCache()
|
||||||
{
|
{
|
||||||
db.Telemetries.DropCache(CacheTag);
|
memoryCache.DropBasic<Telemetry>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime GetLastTelemetryDate(int idTelemetry)
|
public DateTime GetLastTelemetryDate(int idTelemetry)
|
||||||
@ -228,9 +228,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Trace.WriteLine($"Merge() Fail. Rollback. Reason is:{ex.Message}");
|
System.Diagnostics.Trace.WriteLine($"Merge() Fail. Rollback. Reason is:{ex.Message}");
|
||||||
#pragma warning disable CA2016 // Перенаправьте параметр "CancellationToken" в методы
|
await transaction.RollbackAsync(CancellationToken.None);
|
||||||
await transaction.RollbackAsync();
|
|
||||||
#pragma warning restore CA2016 // Перенаправьте параметр "CancellationToken" в методы
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
.Options;
|
.Options;
|
||||||
var db = new AsbCloudDbContext(contextOptions);
|
var db = new AsbCloudDbContext(contextOptions);
|
||||||
|
|
||||||
var cacheTelemetry = memoryCache.GetOrCreateBasic<Telemetry>(db);
|
var cacheTelemetry = memoryCache.GetOrCreateBasic(db.Set<Telemetry>());
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,6 @@ using AsbCloudApp.Repositories;
|
|||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.EfCache;
|
|
||||||
using AsbCloudInfrastructure.Repository;
|
using AsbCloudInfrastructure.Repository;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@ -20,9 +19,6 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
public class WellService : CrudCacheRepositoryBase<WellDto, Well>, IWellService
|
public class WellService : CrudCacheRepositoryBase<WellDto, Well>, IWellService
|
||||||
{
|
{
|
||||||
private const string relationCompaniesWellsCacheTag = "RelationCompaniesWells";
|
|
||||||
private static readonly TimeSpan relationCompaniesWellsCacheObsolence = TimeSpan.FromMinutes(15);
|
|
||||||
|
|
||||||
private readonly ITelemetryService telemetryService;
|
private readonly ITelemetryService telemetryService;
|
||||||
private readonly ICrudRepository<CompanyTypeDto> companyTypesService;
|
private readonly ICrudRepository<CompanyTypeDto> companyTypesService;
|
||||||
private readonly ITimezoneService timezoneService;
|
private readonly ITimezoneService timezoneService;
|
||||||
@ -50,13 +46,18 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Task<IEnumerable<RelationCompanyWell>> GetCacheRelationCompanyWellAsync(CancellationToken token)
|
private Task<IEnumerable<RelationCompanyWell>> GetCacheRelationCompanyWellAsync(CancellationToken token)
|
||||||
=> dbContext.RelationCompaniesWells
|
{
|
||||||
.Include(r => r.Company)
|
var getter = async (CancellationToken token)
|
||||||
.Include(r => r.Well)
|
=> (await dbContext.Set<RelationCompanyWell>()
|
||||||
.FromCacheAsync(relationCompaniesWellsCacheTag, relationCompaniesWellsCacheObsolence, token);
|
.Include(r => r.Company)
|
||||||
|
.Include(r => r.Well)
|
||||||
|
.ToArrayAsync(token))
|
||||||
|
.AsEnumerable();
|
||||||
|
return memoryCache.GetOrCreateBasicAsync(getter, token);
|
||||||
|
}
|
||||||
|
|
||||||
private void DropCacheRelationCompanyWell()
|
private void DropCacheRelationCompanyWell()
|
||||||
=> dbContext.RelationCompaniesWells.DropCache(relationCompaniesWellsCacheTag);
|
=> memoryCache.DropBasic<RelationCompanyWell>();
|
||||||
|
|
||||||
public DateTimeOffset GetLastTelemetryDate(int idWell)
|
public DateTimeOffset GetLastTelemetryDate(int idWell)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user