forked from ddrilling/AsbCloudServer
Remove EfCacheDictionaryExtensions
This commit is contained in:
parent
7cfd60844e
commit
ec3a0e00ef
@ -1,439 +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.
|
|
||||||
/// Кеш не отслеживается ChangeTracker.
|
|
||||||
/// </summary>
|
|
||||||
public static class EfCacheDictionaryExtensions
|
|
||||||
{
|
|
||||||
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 CacheItem
|
|
||||||
{
|
|
||||||
internal IDictionary? Data;
|
|
||||||
internal DateTime DateObsolete;
|
|
||||||
internal DateTime DateObsoleteTotal;
|
|
||||||
internal readonly SemaphoreSlim semaphore = new(1);
|
|
||||||
|
|
||||||
|
|
||||||
internal Dictionary<TKey, TEntity> GetData<TKey, TEntity>()
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
if (Data is Dictionary<TKey, TEntity> typedData)
|
|
||||||
return typedData;
|
|
||||||
throw new TypeAccessException("Cache data has wrong type. Possible 'tag' is not unique.");
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Dictionary<TKey, TModel> GetData<TKey, TEntity, TModel>(Func<TEntity, TModel> convert, int attempt = 1)
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
if (Data is Dictionary<TKey, TModel> typedData)
|
|
||||||
return typedData;
|
|
||||||
if (Data is Dictionary<TKey, TEntity> typedEntityData)
|
|
||||||
{
|
|
||||||
if (semaphore.Wait(0))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var convertedData = typedEntityData.ToDictionary(i => i.Key, i => convert(i.Value));
|
|
||||||
Data = convertedData;
|
|
||||||
return convertedData;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (semaphore.Wait(semaphoreTimeout))
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
throw new TimeoutException("EfCacheL2.GetOrAddCache. Can't wait too long while converting cache data");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (attempt > 0)
|
|
||||||
return GetData<TKey, TEntity, TModel>(convert, --attempt);
|
|
||||||
throw new TypeAccessException("Cache data has wrong type. Possible 'tag' is not unique.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CacheItem GetOrAddCache(string tag, Func<IDictionary> valueFactory, TimeSpan obsolete)
|
|
||||||
{
|
|
||||||
CacheItem cache;
|
|
||||||
while (!caches.ContainsKey(tag))
|
|
||||||
{
|
|
||||||
if (semaphore.Wait(0))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
cache = new CacheItem();
|
|
||||||
caches.Add(tag, cache);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
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<IDictionary>> valueFactoryAsync, TimeSpan obsolete, CancellationToken token)
|
|
||||||
{
|
|
||||||
CacheItem cache;
|
|
||||||
while (!caches.ContainsKey(tag))
|
|
||||||
{
|
|
||||||
if (semaphore.Wait(0))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
cache = new CacheItem();
|
|
||||||
caches.Add(tag, cache);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
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>
|
|
||||||
/// Кешировать запрос в Dictionary<<typeparamref name="TKey"/>, <typeparamref name="TEntity"/>>. С тегом typeof(TEntity).Name и ключом int Id
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TEntity"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Dictionary<int, TEntity> FromCacheDictionary<TEntity>(
|
|
||||||
this IQueryable<TEntity> query)
|
|
||||||
where TEntity : class, AsbCloudDb.Model.IId
|
|
||||||
{
|
|
||||||
var tag = typeof(TEntity).Name;
|
|
||||||
return FromCacheDictionary(query, tag, defaultObsolescence, e => e.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Кешировать запрос в Dictionary<<typeparamref name="TKey"/>, <typeparamref name="TEntity"/>>. С тегом typeof(TEntity).Name
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TKey"></typeparam>
|
|
||||||
/// <typeparam name="TEntity"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="keySelector">Делегат получения ключа из записи</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Dictionary<TKey, TEntity> FromCacheDictionary<TKey, TEntity>(
|
|
||||||
this IQueryable<TEntity> query,
|
|
||||||
Func<TEntity, TKey> keySelector)
|
|
||||||
where TEntity : class
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
var tag = typeof(TEntity).Name;
|
|
||||||
return FromCacheDictionary(query, tag, defaultObsolescence, keySelector);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Кешировать запрос в Dictionary<<typeparamref name="TKey"/>, <typeparamref name="TEntity"/>>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TKey">тип ключа</typeparam>
|
|
||||||
/// <typeparam name="TEntity">тип значения</typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="tag">Метка кеша</param>
|
|
||||||
/// <param name="obsolescence">Период устаревания данных</param>
|
|
||||||
/// <param name="keySelector">Делегат получения ключа из записи</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Dictionary<TKey, TEntity> FromCacheDictionary<TKey, TEntity>(
|
|
||||||
this IQueryable<TEntity> query,
|
|
||||||
string tag,
|
|
||||||
TimeSpan obsolescence,
|
|
||||||
Func<TEntity, TKey> keySelector)
|
|
||||||
where TEntity : class
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
IDictionary factory()
|
|
||||||
=> query.AsNoTracking().ToDictionary(keySelector);
|
|
||||||
var cache = GetOrAddCache(tag, factory, obsolescence);
|
|
||||||
return cache.GetData<TKey, TEntity>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Кешировать запрос с последующим преобразованием из <typeparamref name="TEntity"/> в <typeparamref name="TModel"/>.<br/>
|
|
||||||
/// Преобразование выполняется после получения из БД, результат кешируется в Dictionary<<typeparamref name="TKey"/>, <typeparamref name="TModel"/>>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TKey">тип ключа</typeparam>
|
|
||||||
/// <typeparam name="TEntity">тип значения</typeparam>
|
|
||||||
/// <typeparam name="TModel"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="tag">Метка кеша</param>
|
|
||||||
/// <param name="obsolescence">Период устаревания данных</param>
|
|
||||||
/// <param name="keySelector">Делегат получения ключа из записи</param>
|
|
||||||
/// <param name="convert">Преобразование данных БД в DTO</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Dictionary<TKey, TModel> FromCacheDictionary<TKey, TEntity, TModel>(
|
|
||||||
this IQueryable<TEntity> query,
|
|
||||||
string tag,
|
|
||||||
TimeSpan obsolescence,
|
|
||||||
Func<TEntity, TKey> keySelector,
|
|
||||||
Func<TEntity, TModel> convert)
|
|
||||||
where TEntity : class
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
IDictionary factory()
|
|
||||||
=> query.AsNoTracking().ToDictionary(keySelector);
|
|
||||||
var cache = GetOrAddCache(tag, factory, obsolescence);
|
|
||||||
return cache.GetData<TKey, TEntity, TModel>(convert);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Асинхронно кешировать запрос в Dictionary<<typeparamref name="TKey"/>, <typeparamref name="TEntity"/>>. С тегом typeof(TEntity).Name и ключом int Id
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TEntity"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Task<Dictionary<int, TEntity>> FromCacheDictionaryAsync<TEntity>(
|
|
||||||
this IQueryable<TEntity> query,
|
|
||||||
CancellationToken token = default)
|
|
||||||
where TEntity : class, AsbCloudDb.Model.IId
|
|
||||||
{
|
|
||||||
var tag = typeof(TEntity).Name;
|
|
||||||
return FromCacheDictionaryAsync(query, tag, defaultObsolescence, e => e.Id, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Асинхронно кешировать запрос в Dictionary<<typeparamref name="TKey"/>, <typeparamref name="TEntity"/>>. С тегом typeof(TEntity).Name
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TKey"></typeparam>
|
|
||||||
/// <typeparam name="TEntity"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="keySelector">Делегат получения ключа из записи</param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Task<Dictionary<TKey, TEntity>> FromCacheDictionaryAsync<TKey, TEntity>(
|
|
||||||
this IQueryable<TEntity> query,
|
|
||||||
Func<TEntity, TKey> keySelector,
|
|
||||||
CancellationToken token = default)
|
|
||||||
where TEntity : class
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
var tag = typeof(TEntity).Name;
|
|
||||||
return FromCacheDictionaryAsync(query, tag, defaultObsolescence, keySelector, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Асинхронно кешировать запрос в Dictionary<<typeparamref name="TKey"/>, <typeparamref name="TEntity"/>>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TKey">тип ключа</typeparam>
|
|
||||||
/// <typeparam name="TEntity">тип значения</typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="tag">Метка кеша</param>
|
|
||||||
/// <param name="obsolescence">Период устаревания данных</param>
|
|
||||||
/// <param name="keySelector">Делегат получения ключа из записи</param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<Dictionary<TKey, TEntity>> FromCacheDictionaryAsync<TKey, TEntity>(
|
|
||||||
this IQueryable<TEntity> query,
|
|
||||||
string tag,
|
|
||||||
TimeSpan obsolescence,
|
|
||||||
Func<TEntity, TKey> keySelector,
|
|
||||||
CancellationToken token = default)
|
|
||||||
where TEntity : class
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
async Task<IDictionary> factory(CancellationToken token)
|
|
||||||
=> await query.AsNoTracking().ToDictionaryAsync(keySelector, token);
|
|
||||||
var cache = await GetOrAddCacheAsync(tag, factory, obsolescence, token);
|
|
||||||
return cache.GetData<TKey, TEntity>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Асинхронно кешировать запрос с последующим преобразованием из <typeparamref name="TEntity"/> в <typeparamref name="TModel"/>.<br/>
|
|
||||||
/// Преобразование выполняется после получения из БД, результат кешируется в Dictionary<<typeparamref name="TKey"/>, <typeparamref name="TModel"/>>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TKey">тип ключа</typeparam>
|
|
||||||
/// <typeparam name="TEntity">тип значения</typeparam>
|
|
||||||
/// <typeparam name="TModel"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="tag">Метка кеша</param>
|
|
||||||
/// <param name="obsolescence">Период устаревания данных</param>
|
|
||||||
/// <param name="keySelector">Делегат получения ключа из записи</param>
|
|
||||||
/// <param name="convert">Преобразование данных БД в DTO</param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<Dictionary<TKey, TModel>> FromCacheDictionaryAsync<TKey, TEntity, TModel>(this IQueryable<TEntity> query, string tag, TimeSpan obsolescence, Func<TEntity, TKey> keySelector, Func<TEntity, TModel> convert, CancellationToken token = default)
|
|
||||||
where TEntity : class
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
async Task<IDictionary> factory(CancellationToken token)
|
|
||||||
=> await query.AsNoTracking().ToDictionaryAsync(keySelector, token);
|
|
||||||
var cache = await GetOrAddCacheAsync(tag, factory, obsolescence, token);
|
|
||||||
return cache.GetData<TKey, TEntity, TModel>(convert);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// drops cache with tag = typeof(T).Name
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
public static void DropCacheDictionary<T>(this IQueryable<T> query)
|
|
||||||
{
|
|
||||||
var tag = typeof(T).Name;
|
|
||||||
DropCacheDictionary<T>(query, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Очистить кеш
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="tag">Метка кеша</param>
|
|
||||||
public static void DropCacheDictionary<T>(this IQueryable<T> query, string tag)
|
|
||||||
{
|
|
||||||
caches.Remove(tag, out var _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#nullable disable
|
|
||||||
}
|
|
@ -349,7 +349,7 @@ namespace AsbCloudInfrastructure.EfCache
|
|||||||
return cache.GetData(convert);
|
return cache.GetData(convert);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<IEnumerable<TEntity>> FromCacheAsync<TEntity>(this IQueryable<TEntity> query, CancellationToken token = default)
|
public static Task<IEnumerable<TEntity>> FromCacheAsync<TEntity>(this IQueryable<TEntity> query, CancellationToken token)
|
||||||
where TEntity : class
|
where TEntity : class
|
||||||
{
|
{
|
||||||
var tag = typeof(TEntity).Name;
|
var tag = typeof(TEntity).Name;
|
||||||
@ -365,7 +365,7 @@ namespace AsbCloudInfrastructure.EfCache
|
|||||||
/// <param name="obsolescence">Период устаревания данных</param>
|
/// <param name="obsolescence">Период устаревания данных</param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<IEnumerable<TEntity>> FromCacheAsync<TEntity>(this IQueryable<TEntity> query, string tag, TimeSpan obsolescence, CancellationToken token = default)
|
public static async Task<IEnumerable<TEntity>> FromCacheAsync<TEntity>(this IQueryable<TEntity> query, string tag, TimeSpan obsolescence, CancellationToken token)
|
||||||
where TEntity : class
|
where TEntity : class
|
||||||
{
|
{
|
||||||
async Task<object[]> factory(CancellationToken token)
|
async Task<object[]> factory(CancellationToken token)
|
||||||
@ -386,7 +386,7 @@ namespace AsbCloudInfrastructure.EfCache
|
|||||||
/// <param name="convert">Преобразование данных БД в DTO</param>
|
/// <param name="convert">Преобразование данных БД в DTO</param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <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 = default)
|
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
|
where TEntity : class
|
||||||
{
|
{
|
||||||
async Task<object[]> factory(CancellationToken token)
|
async Task<object[]> factory(CancellationToken token)
|
||||||
|
@ -54,7 +54,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
public override async Task<IEnumerable<TDto>> GetAllAsync(CancellationToken token)
|
public override async Task<IEnumerable<TDto>> GetAllAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
var cache = await GetCacheAsync(token);
|
var cache = await GetCacheAsync(token);
|
||||||
return cache.Values;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -65,14 +65,14 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
public override TDto? GetOrDefault(int id)
|
public override TDto? GetOrDefault(int id)
|
||||||
{
|
{
|
||||||
var cache = GetCache();
|
var cache = GetCache();
|
||||||
return cache.GetValueOrDefault(id);
|
return cache.FirstOrDefault(d => d.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override async Task<TDto?> GetOrDefaultAsync(int id, CancellationToken token)
|
public override async Task<TDto?> GetOrDefaultAsync(int id, CancellationToken token)
|
||||||
{
|
{
|
||||||
var cache = await GetCacheAsync(token);
|
var cache = await GetCacheAsync(token);
|
||||||
return cache.GetValueOrDefault(id);
|
return cache.FirstOrDefault(d => d.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@ -102,17 +102,17 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Task<Dictionary<int, TDto>> GetCacheAsync(CancellationToken token)
|
protected virtual Task<IEnumerable<TDto>> GetCacheAsync(CancellationToken token)
|
||||||
=> GetQuery()
|
=> GetQuery()
|
||||||
.FromCacheDictionaryAsync(CacheTag, CacheOlescence, KeySelector, Convert, token);
|
.FromCacheAsync(CacheTag, CacheOlescence, Convert, token);
|
||||||
|
|
||||||
|
|
||||||
protected virtual Dictionary<int, TDto> GetCache()
|
protected virtual IEnumerable<TDto> GetCache()
|
||||||
=> GetQuery()
|
=> GetQuery()
|
||||||
.FromCacheDictionary(CacheTag, CacheOlescence, KeySelector, Convert);
|
.FromCache(CacheTag, CacheOlescence, Convert);
|
||||||
|
|
||||||
protected virtual void DropCache()
|
protected virtual void DropCache()
|
||||||
=> dbSet.DropCacheDictionary(CacheTag);
|
=> dbSet.DropCache(CacheTag);
|
||||||
}
|
}
|
||||||
#nullable disable
|
#nullable disable
|
||||||
}
|
}
|
@ -23,25 +23,25 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
public CrudWellRelatedCacheServiceBase(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
public CrudWellRelatedCacheServiceBase(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
||||||
: base(context, makeQuery) { }
|
: base(context, makeQuery) { }
|
||||||
|
|
||||||
public async Task<IEnumerable<TDto>> GetByIdWellAsync(int idWell, CancellationToken token)
|
public async Task<IEnumerable<TDto>?> GetByIdWellAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var cache = await GetCacheAsync(token);
|
var cache = await GetCacheAsync(token);
|
||||||
|
|
||||||
var dtos = cache.Values
|
var dtos = cache
|
||||||
.Where(e => e.IdWell == idWell)
|
.Where(e => e.IdWell == idWell)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<TDto>> GetByIdWellAsync(IEnumerable<int> idsWells, CancellationToken token)
|
public async Task<IEnumerable<TDto>?> GetByIdWellAsync(IEnumerable<int> idsWells, CancellationToken token)
|
||||||
{
|
{
|
||||||
if (!idsWells.Any())
|
if (!idsWells.Any())
|
||||||
return Enumerable.Empty<TDto>();
|
return Enumerable.Empty<TDto>();
|
||||||
|
|
||||||
var cache = await GetCacheAsync(token);
|
var cache = await GetCacheAsync(token);
|
||||||
|
|
||||||
var dtos = cache.Values
|
var dtos = cache
|
||||||
.Where(e => idsWells.Contains(e.IdWell))
|
.Where(e => idsWells.Contains(e.IdWell))
|
||||||
.ToList();
|
.ToList();
|
||||||
return dtos;
|
return dtos;
|
||||||
|
@ -23,7 +23,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
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) { }
|
||||||
|
|
||||||
public async Task<IEnumerable<TDto>> GetByIdWellAsync(int idWell, CancellationToken token)
|
public async Task<IEnumerable<TDto>?> GetByIdWellAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var entities = await GetQuery()
|
var entities = await GetQuery()
|
||||||
.Where(e => e.IdWell == idWell)
|
.Where(e => e.IdWell == idWell)
|
||||||
@ -32,7 +32,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<TDto>> GetByIdWellAsync(IEnumerable<int> idsWells, CancellationToken token)
|
public async Task<IEnumerable<TDto>?> GetByIdWellAsync(IEnumerable<int> idsWells, CancellationToken token)
|
||||||
{
|
{
|
||||||
if (!idsWells.Any())
|
if (!idsWells.Any())
|
||||||
return Enumerable.Empty<TDto>();
|
return Enumerable.Empty<TDto>();
|
||||||
|
@ -15,15 +15,15 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
: base(context)
|
: base(context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Перенести в сервис "дело скважины"
|
//TODO: Перенести в сервис "дело скважины"
|
||||||
public async Task<IEnumerable<FileCategoryDto>> GetWellCaseCategoriesAsync(CancellationToken token)
|
public async Task<IEnumerable<FileCategoryDto>> GetWellCaseCategoriesAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
var cache = await GetCacheAsync(token)
|
var cache = await GetCacheAsync(token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
var dtos = cache
|
var dtos = cache
|
||||||
.Where(kv => kv.Key >= 10000)
|
.Where(f => f.Id >= 10000)
|
||||||
.Where(kv => kv.Key <= 20000)
|
.Where(f => f.Id <= 20000);
|
||||||
.Select(kv => kv.Value);
|
|
||||||
|
|
||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
@ -123,18 +123,12 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
|
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
Well[] wells = Array.Empty<Well>();
|
Well[] wells = Array.Empty<Well>();
|
||||||
try
|
|
||||||
{
|
|
||||||
wells = db.Set<Well>()
|
wells = db.Set<Well>()
|
||||||
.Include(well => well.Telemetry)
|
.Include(well => well.Telemetry)
|
||||||
.Include(well => well.Cluster)
|
.Include(well => well.Cluster)
|
||||||
.Where(well => well.IdTelemetry != null)
|
.Where(well => well.IdTelemetry != null)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
foreach (Well well in wells)
|
foreach (Well well in wells)
|
||||||
{
|
{
|
||||||
var capacity = well.IdState == 1
|
var capacity = well.IdState == 1
|
||||||
|
@ -47,7 +47,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
|
|
||||||
private void DropTelemetryCache()
|
private void DropTelemetryCache()
|
||||||
{
|
{
|
||||||
db.Telemetries.DropCacheDictionary(telemetryCacheTag);
|
db.Telemetries.DropCache(telemetryCacheTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime GetLastTelemetryDate(int idTelemetry)
|
public DateTime GetLastTelemetryDate(int idTelemetry)
|
||||||
|
@ -81,8 +81,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
.Select(r => r.IdWell);
|
.Select(r => r.IdWell);
|
||||||
|
|
||||||
var wellsDtos = (await GetCacheAsync(token))
|
var wellsDtos = (await GetCacheAsync(token))
|
||||||
.Where(kv => wellsIds.Contains(kv.Key))
|
.Where(w => wellsIds.Contains(w.Id));
|
||||||
.Select(kv => kv.Value);
|
|
||||||
|
|
||||||
return wellsDtos.ToList();
|
return wellsDtos.ToList();
|
||||||
}
|
}
|
||||||
@ -95,7 +94,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
if (dto.IdState is < 0 or > 2)
|
if (dto.IdState is < 0 or > 2)
|
||||||
throw new ArgumentInvalidException("Текущее состояние работы скважины указано неправильно.", nameof(dto));
|
throw new ArgumentInvalidException("Текущее состояние работы скважины указано неправильно.", nameof(dto));
|
||||||
|
|
||||||
if (dto.Id != 0 && (await GetCacheAsync(token)).ContainsKey(dto.Id))
|
if (dto.Id != 0 && (await GetCacheAsync(token)).Any(w => w.Id == dto.Id))
|
||||||
throw new ArgumentInvalidException($"Нельзя повторно добавить скважину с id: {dto.Id}", nameof(dto));
|
throw new ArgumentInvalidException($"Нельзя повторно добавить скважину с id: {dto.Id}", nameof(dto));
|
||||||
|
|
||||||
var entity = Convert(dto);
|
var entity = Convert(dto);
|
||||||
@ -194,7 +193,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
|
|
||||||
var cache = await GetCacheAsync(token);
|
var cache = await GetCacheAsync(token);
|
||||||
|
|
||||||
var clusterWellsIds = cache.Values
|
var clusterWellsIds = cache
|
||||||
.Where((w) => w.IdCluster == well.IdCluster)
|
.Where((w) => w.IdCluster == well.IdCluster)
|
||||||
.Select(w => w.Id);
|
.Select(w => w.Id);
|
||||||
|
|
||||||
@ -247,7 +246,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
public async Task EnshureTimezonesIsSetAsync(CancellationToken token)
|
public async Task EnshureTimezonesIsSetAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
var cache = await GetCacheAsync(token);
|
var cache = await GetCacheAsync(token);
|
||||||
if (!cache.Values.Any(w => w.Timezone is null))
|
if (!cache.Any(w => w.Timezone is null))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var defaultTimeZone = new SimpleTimezone
|
var defaultTimeZone = new SimpleTimezone
|
||||||
|
Loading…
Reference in New Issue
Block a user