diff --git a/AsbCloudInfrastructure/EfCache/EfCacheDictionaryExtensions.cs b/AsbCloudInfrastructure/EfCache/EfCacheDictionaryExtensions.cs
deleted file mode 100644
index 033a3d47..00000000
--- a/AsbCloudInfrastructure/EfCache/EfCacheDictionaryExtensions.cs
+++ /dev/null
@@ -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
- ///
- /// Кеширование запросов EF.
- /// Кеш не отслеживается ChangeTracker.
- ///
- public static class EfCacheDictionaryExtensions
- {
- private static readonly Dictionary 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 GetData()
- where TKey : notnull
- {
- if (Data is Dictionary typedData)
- return typedData;
- throw new TypeAccessException("Cache data has wrong type. Possible 'tag' is not unique.");
- }
-
- internal Dictionary GetData(Func convert, int attempt = 1)
- where TKey : notnull
- {
- if (Data is Dictionary typedData)
- return typedData;
- if (Data is Dictionary 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(convert, --attempt);
- throw new TypeAccessException("Cache data has wrong type. Possible 'tag' is not unique.");
- }
- }
-
- private static CacheItem GetOrAddCache(string tag, Func 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 GetOrAddCacheAsync(string tag, Func> 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;
- }
-
- ///
- /// Кешировать запрос в Dictionary<, >. С тегом typeof(TEntity).Name и ключом int Id
- ///
- ///
- ///
- ///
- public static Dictionary FromCacheDictionary(
- this IQueryable query)
- where TEntity : class, AsbCloudDb.Model.IId
- {
- var tag = typeof(TEntity).Name;
- return FromCacheDictionary(query, tag, defaultObsolescence, e => e.Id);
- }
-
- ///
- /// Кешировать запрос в Dictionary<, >. С тегом typeof(TEntity).Name
- ///
- ///
- ///
- ///
- /// Делегат получения ключа из записи
- ///
- public static Dictionary FromCacheDictionary(
- this IQueryable query,
- Func keySelector)
- where TEntity : class
- where TKey : notnull
- {
- var tag = typeof(TEntity).Name;
- return FromCacheDictionary(query, tag, defaultObsolescence, keySelector);
- }
-
- ///
- /// Кешировать запрос в Dictionary<, >.
- ///
- /// тип ключа
- /// тип значения
- ///
- /// Метка кеша
- /// Период устаревания данных
- /// Делегат получения ключа из записи
- ///
- public static Dictionary FromCacheDictionary(
- this IQueryable query,
- string tag,
- TimeSpan obsolescence,
- Func keySelector)
- where TEntity : class
- where TKey : notnull
- {
- IDictionary factory()
- => query.AsNoTracking().ToDictionary(keySelector);
- var cache = GetOrAddCache(tag, factory, obsolescence);
- return cache.GetData();
- }
-
- ///
- /// Кешировать запрос с последующим преобразованием из в .
- /// Преобразование выполняется после получения из БД, результат кешируется в Dictionary<, >.
- ///
- /// тип ключа
- /// тип значения
- ///
- ///
- /// Метка кеша
- /// Период устаревания данных
- /// Делегат получения ключа из записи
- /// Преобразование данных БД в DTO
- ///
- public static Dictionary FromCacheDictionary(
- this IQueryable query,
- string tag,
- TimeSpan obsolescence,
- Func keySelector,
- Func convert)
- where TEntity : class
- where TKey : notnull
- {
- IDictionary factory()
- => query.AsNoTracking().ToDictionary(keySelector);
- var cache = GetOrAddCache(tag, factory, obsolescence);
- return cache.GetData(convert);
- }
-
- ///
- /// Асинхронно кешировать запрос в Dictionary<, >. С тегом typeof(TEntity).Name и ключом int Id
- ///
- ///
- ///
- ///
- ///
- public static Task> FromCacheDictionaryAsync(
- this IQueryable query,
- CancellationToken token = default)
- where TEntity : class, AsbCloudDb.Model.IId
- {
- var tag = typeof(TEntity).Name;
- return FromCacheDictionaryAsync(query, tag, defaultObsolescence, e => e.Id, token);
- }
-
- ///
- /// Асинхронно кешировать запрос в Dictionary<, >. С тегом typeof(TEntity).Name
- ///
- ///
- ///
- ///
- /// Делегат получения ключа из записи
- ///
- ///
- public static Task> FromCacheDictionaryAsync(
- this IQueryable query,
- Func keySelector,
- CancellationToken token = default)
- where TEntity : class
- where TKey : notnull
- {
- var tag = typeof(TEntity).Name;
- return FromCacheDictionaryAsync(query, tag, defaultObsolescence, keySelector, token);
- }
-
-
- ///
- /// Асинхронно кешировать запрос в Dictionary<, >.
- ///
- /// тип ключа
- /// тип значения
- ///
- /// Метка кеша
- /// Период устаревания данных
- /// Делегат получения ключа из записи
- ///
- ///
- public static async Task> FromCacheDictionaryAsync(
- this IQueryable query,
- string tag,
- TimeSpan obsolescence,
- Func keySelector,
- CancellationToken token = default)
- where TEntity : class
- where TKey : notnull
- {
- async Task factory(CancellationToken token)
- => await query.AsNoTracking().ToDictionaryAsync(keySelector, token);
- var cache = await GetOrAddCacheAsync(tag, factory, obsolescence, token);
- return cache.GetData();
- }
-
- ///
- /// Асинхронно кешировать запрос с последующим преобразованием из в .
- /// Преобразование выполняется после получения из БД, результат кешируется в Dictionary<, >.
- ///
- /// тип ключа
- /// тип значения
- ///
- ///
- /// Метка кеша
- /// Период устаревания данных
- /// Делегат получения ключа из записи
- /// Преобразование данных БД в DTO
- ///
- ///
- public static async Task> FromCacheDictionaryAsync(this IQueryable query, string tag, TimeSpan obsolescence, Func keySelector, Func convert, CancellationToken token = default)
- where TEntity : class
- where TKey : notnull
- {
- async Task factory(CancellationToken token)
- => await query.AsNoTracking().ToDictionaryAsync(keySelector, token);
- var cache = await GetOrAddCacheAsync(tag, factory, obsolescence, token);
- return cache.GetData(convert);
- }
-
- ///
- /// drops cache with tag = typeof(T).Name
- ///
- ///
- ///
- public static void DropCacheDictionary(this IQueryable query)
- {
- var tag = typeof(T).Name;
- DropCacheDictionary(query, tag);
- }
-
- ///
- /// Очистить кеш
- ///
- ///
- ///
- /// Метка кеша
- public static void DropCacheDictionary(this IQueryable query, string tag)
- {
- caches.Remove(tag, out var _);
- }
- }
-#nullable disable
-}
diff --git a/AsbCloudInfrastructure/EfCache/EfCacheExtensions.cs b/AsbCloudInfrastructure/EfCache/EfCacheExtensions.cs
index 0a93c70c..c618534d 100644
--- a/AsbCloudInfrastructure/EfCache/EfCacheExtensions.cs
+++ b/AsbCloudInfrastructure/EfCache/EfCacheExtensions.cs
@@ -349,7 +349,7 @@ namespace AsbCloudInfrastructure.EfCache
return cache.GetData(convert);
}
- public static Task> FromCacheAsync(this IQueryable query, CancellationToken token = default)
+ public static Task> FromCacheAsync(this IQueryable query, CancellationToken token)
where TEntity : class
{
var tag = typeof(TEntity).Name;
@@ -365,7 +365,7 @@ namespace AsbCloudInfrastructure.EfCache
/// Период устаревания данных
///
///
- public static async Task> FromCacheAsync(this IQueryable query, string tag, TimeSpan obsolescence, CancellationToken token = default)
+ public static async Task> FromCacheAsync(this IQueryable query, string tag, TimeSpan obsolescence, CancellationToken token)
where TEntity : class
{
async Task