diff --git a/AsbCloudInfrastructure/EfCache/EfCacheExtensions.cs b/AsbCloudInfrastructure/EfCache/EfCacheExtensions.cs index 8d993c21..c2eec646 100644 --- a/AsbCloudInfrastructure/EfCache/EfCacheExtensions.cs +++ b/AsbCloudInfrastructure/EfCache/EfCacheExtensions.cs @@ -21,46 +21,74 @@ namespace AsbCloudInfrastructure.EfCache private static readonly TimeSpan minCacheTime = TimeSpan.FromSeconds(2); private static readonly TimeSpan defaultObsolescence = TimeSpan.FromMinutes(4); - private class YeldConvertedData : IEnumerable + private class YieldConvertedData : IEnumerable { - IEnumerable data; - public YeldConvertedData(IEnumerable entities, Func convert) + private struct ConvertedData { - data = entities; + public TEntity? Entity; + public TModel? Model; } - class Enumerator : IEnumerator - { - private readonly IEnumerable data; + ConvertedData[] data; + public Func convert { get; } - public Enumerator( IEnumerable data, Func convert) + public YieldConvertedData(TEntity[] entities, Func convert) + { + data = (entities.Select(x => new ConvertedData { + Entity = x, + Model = default })) + .ToArray(); + this.convert = convert; + } + + class YieldConvertedDataEnumerator : IEnumerator + { + private readonly ConvertedData[] data; + private readonly Func convert; + private int position = -1; + + public YieldConvertedDataEnumerator(ConvertedData[] data, Func convert) { this.data = data; + this.convert = convert; } - public TModel Current => throw new NotImplementedException(); + 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 => throw new NotImplementedException(); + object IEnumerator.Current => Current!; public void Dispose() { - throw new NotImplementedException(); } public bool MoveNext() { - throw new NotImplementedException(); + position++; + return (position < data.Length); } public void Reset() - { - throw new NotImplementedException(); + { + position = -1; } } public IEnumerator GetEnumerator() { - throw new NotImplementedException(); + var result = new YieldConvertedDataEnumerator(data, convert); + return result; } IEnumerator IEnumerable.GetEnumerator() @@ -93,7 +121,7 @@ namespace AsbCloudInfrastructure.EfCache { try { - var convertedData = typedEntityData.Select(convert).ToArray(); + var convertedData = new YieldConvertedData(typedEntityData.ToArray(), convert); Data = convertedData; return convertedData; } @@ -111,7 +139,7 @@ namespace AsbCloudInfrastructure.EfCache else { semaphore.Release(); - throw new TimeoutException("EfCacheL2.GetOrAddCache. Can't wait too long while converting cache data"); + throw new TimeoutException("EfCacheL2.GetData. Can't wait too long while converting cache data"); } } } @@ -121,7 +149,7 @@ namespace AsbCloudInfrastructure.EfCache } } - private static CacheItem GetOrAddCache(string tag, Func valueFactory, TimeSpan obsolete) + private static CacheItem GetOrAddCache(string tag, Func valueFactory, TimeSpan obsolete) { CacheItem cache; while (!caches.ContainsKey(tag)) @@ -194,7 +222,7 @@ namespace AsbCloudInfrastructure.EfCache return cache; } - private static async Task GetOrAddCacheAsync(string tag, Func> valueFactoryAsync, TimeSpan obsolete, CancellationToken token) + private static async Task GetOrAddCacheAsync(string tag, Func> valueFactoryAsync, TimeSpan obsolete, CancellationToken token) { CacheItem cache; while (!caches.ContainsKey(tag)) @@ -291,7 +319,7 @@ namespace AsbCloudInfrastructure.EfCache public static IEnumerable FromCache(this IQueryable query, string tag, TimeSpan obsolescence) where TEntity : class { - IEnumerable factory() => query.AsNoTracking().ToList(); + object[] factory() => query.AsNoTracking().ToArray(); var cache = GetOrAddCache(tag, factory, obsolescence); return cache.GetData(); } @@ -310,7 +338,7 @@ namespace AsbCloudInfrastructure.EfCache public static IEnumerable FromCache(this IQueryable query, string tag, TimeSpan obsolescence, Func convert) where TEntity : class { - IEnumerable factory() => query.AsNoTracking().ToList(); + object[] factory() => query.AsNoTracking().ToArray(); var cache = GetOrAddCache(tag, factory, obsolescence); return cache.GetData(convert); } @@ -334,8 +362,8 @@ namespace AsbCloudInfrastructure.EfCache public static async Task> FromCacheAsync(this IQueryable query, string tag, TimeSpan obsolescence, CancellationToken token = default) where TEntity : class { - async Task factory(CancellationToken token) - => await query.AsNoTracking().ToListAsync(token); + async Task factory(CancellationToken token) + => await query.AsNoTracking().ToArrayAsync(token); var cache = await GetOrAddCacheAsync(tag, factory, obsolescence, token); return cache.GetData(); } @@ -355,8 +383,8 @@ namespace AsbCloudInfrastructure.EfCache public static async Task> FromCacheAsync(this IQueryable query, string tag, TimeSpan obsolescence, Func convert, CancellationToken token = default) where TEntity : class { - async Task factory(CancellationToken token) - => await query.AsNoTracking().ToListAsync(token); + async Task factory(CancellationToken token) + => await query.AsNoTracking().ToArrayAsync(token); var cache = await GetOrAddCacheAsync(tag, factory, obsolescence, token); return cache.GetData(convert); } diff --git a/AsbCloudInfrastructure/Repository/UserRoleRepository.cs b/AsbCloudInfrastructure/Repository/UserRoleRepository.cs index 1e83ccb7..91b4a3b1 100644 --- a/AsbCloudInfrastructure/Repository/UserRoleRepository.cs +++ b/AsbCloudInfrastructure/Repository/UserRoleRepository.cs @@ -105,7 +105,8 @@ namespace AsbCloudInfrastructure.Repository public IEnumerable GetNestedById(int id, int recursionLevel = 7) { - var dto = GetCacheUserRole().FirstOrDefault(r => r.Id == id); + var dto = GetCacheUserRole() + .FirstOrDefault(r => r.Id == id); if (dto is null) return Enumerable.Empty(); var role = Convert(dto); @@ -253,7 +254,7 @@ namespace AsbCloudInfrastructure.Repository .Include(r => r.RelationUserRoleUserRoles) .FromCache(userRoleCacheTag, relationCacheObsolence, Convert); private void DropCacheUserRole() - => dbContext.RelationUserUserRoles.DropCache(relationUserRoleUserRoleCacheTag); + => dbContext.RelationUserUserRoles.DropCache(userRoleCacheTag); private Task> GetCacheRelationUserRoleUserRoleAsync(CancellationToken token) => dbContext.RelationUserRoleUserRoles @@ -294,12 +295,10 @@ namespace AsbCloudInfrastructure.Repository if (entity.RelationUserRoleUserRoles?.Any() == true) { var rolesCache = GetCacheUserRole(); - dto.Roles = entity.RelationUserRoleUserRoles.Select(rel => - { - var dto = rolesCache.First(r => r.Id == rel.IdInclude); - var includedRole = Convert(dto); - return Convert(includedRole); - }).ToArray(); + dto.Roles = entity.RelationUserRoleUserRoles + .Select(rel => rolesCache + .First(r => r.Id == rel.IdInclude)) + .ToArray(); } return dto; } diff --git a/AsbCloudInfrastructure/Services/FileCategoryService.cs b/AsbCloudInfrastructure/Services/FileCategoryService.cs index 3bb8326e..2b30583e 100644 --- a/AsbCloudInfrastructure/Services/FileCategoryService.cs +++ b/AsbCloudInfrastructure/Services/FileCategoryService.cs @@ -15,7 +15,7 @@ namespace AsbCloudInfrastructure.Services : base(context) { } - + //TODO: Перенести в сервис "дело скважины" public async Task> GetWellCaseCategoriesAsync(CancellationToken token) { var cache = await GetCacheAsync(token)