using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services.Cache { class CacheTable : ICacheTable where TEntity : class { private readonly DbContext context; private List entities; internal CacheTable(DbContext context, List entities) { this.context = context; this.entities = entities; } public TEntity this[int index] { get => entities.ElementAt(index); } public int Refresh() { entities.Clear(); var dbEntities = context.Set().ToList(); entities.AddRange(dbEntities); return entities.Count(); } public async Task RefreshAsync(CancellationToken token = default) { entities.Clear(); var dbEntities = await context.Set().ToListAsync(token).ConfigureAwait(false); entities.AddRange(dbEntities); return entities.Count(); } private bool CheckRefresh(RefreshMode refreshMode) { if (refreshMode == RefreshMode.Force) { Refresh(); return true; } if ((!entities.Any()) && (refreshMode == RefreshMode.IfResultEmpty)) { Refresh(); return true; } return false; } private async Task CheckRefreshAsync(RefreshMode refreshMode, CancellationToken token = default) { if (refreshMode == RefreshMode.Force) { await RefreshAsync(token); return true; } if ((!entities.Any()) && (refreshMode == RefreshMode.IfResultEmpty)) { await RefreshAsync(token); return true; } return false; } public bool Contains(Func predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty) => FirstOrDefault(predicate, refreshMode) != default; public Task ContainsAsync(Func predicate, CancellationToken token = default) => ContainsAsync(predicate, RefreshMode.IfResultEmpty, token); public async Task ContainsAsync(Func predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default) => await FirstOrDefaultAsync(predicate, refreshMode, token) != default; public Task FirstOrDefaultAsync(CancellationToken token = default) => FirstOrDefaultAsync(RefreshMode.IfResultEmpty, token); public TEntity FirstOrDefault(RefreshMode refreshMode = RefreshMode.IfResultEmpty) { bool isUpdated = CheckRefresh(refreshMode); var result = entities.FirstOrDefault(); if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated) { Refresh(); return entities.FirstOrDefault(); } return result; } public async Task FirstOrDefaultAsync(RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default) { bool isUpdated = await CheckRefreshAsync(refreshMode, token); var result = entities.FirstOrDefault(); if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated) { await RefreshAsync(token); return entities.FirstOrDefault(); } return result; } public Task FirstOrDefaultAsync(Func predicate, CancellationToken token = default) => FirstOrDefaultAsync(predicate, RefreshMode.IfResultEmpty, token); public TEntity FirstOrDefault(Func predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty) { bool isUpdated = CheckRefresh(refreshMode); var result = entities.FirstOrDefault(predicate); if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated) { Refresh(); return entities.FirstOrDefault(predicate); } return result; } public async Task FirstOrDefaultAsync(Func predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default) { bool isUpdated = await CheckRefreshAsync(refreshMode, token); var result = entities.FirstOrDefault(predicate); if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated) { await RefreshAsync(token); return entities.FirstOrDefault(predicate); } return result; } public Task> SelectAsync(Func predicate, CancellationToken token = default) => SelectAsync(predicate, RefreshMode.IfResultEmpty, token); public IEnumerable Select(Func predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty) { bool isUpdated = CheckRefresh(refreshMode); var result = entities.Where(predicate); if (!result.Any() && refreshMode == RefreshMode.IfResultEmpty && !isUpdated) { Refresh(); return entities.Where(predicate); } return result; } public async Task> SelectAsync(Func predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default) { bool isUpdated = await CheckRefreshAsync(refreshMode, token); var result = entities.Where(predicate); if (!result.Any() && refreshMode == RefreshMode.IfResultEmpty && !isUpdated) { await RefreshAsync(token); return entities.Where(predicate); } return result; } public IEnumerable Update(Func predicate, Action mutation) { var dbSet = context.Set(); var dbEntities = dbSet.Where(predicate); if (dbEntities.Any()) { foreach (var dbEntity in dbEntities) mutation(dbEntity); context.SaveChanges(); } entities.RemoveAll(e => predicate(e)); entities.AddRange(dbEntities); return dbEntities; } public async Task> UpdateAsync(Func predicate, Action mutation, CancellationToken token = default) { var dbSet = context.Set(); var dbEntities = dbSet.Where(predicate); if (dbEntities.Any()) { foreach (var dbEntity in dbEntities) mutation(dbEntity); await context.SaveChangesAsync(token).ConfigureAwait(false); } entities.RemoveAll(e => predicate(e)); entities.AddRange(dbEntities); return dbEntities; } public void Remove(Func predicate) { var dbSet = context.Set(); entities.RemoveAll(e => predicate(e)); dbSet.RemoveRange(dbSet.Where(predicate)); context.SaveChanges(); return; } public async Task RemoveAsync(Func predicate, CancellationToken token = default) { var dbSet = context.Set(); entities.RemoveAll(e => predicate(e)); dbSet.RemoveRange(dbSet.Where(predicate)); await context.SaveChangesAsync(token).ConfigureAwait(false); return; } public TEntity Insert(TEntity entity) { var dbSet = context.Set(); var dbEntity = dbSet.Add(entity).Entity; context.SaveChanges(); entities.Add(dbEntity); return dbEntity; } public async Task InsertAsync(TEntity entity, CancellationToken token = default) { var dbSet = context.Set(); var dbEntity = dbSet.Add(entity).Entity; await context.SaveChangesAsync(token).ConfigureAwait(false); entities.Add(dbEntity); return dbEntity; } public IEnumerable Insert(IEnumerable newEntities) { var dbSet = context.Set(); var dbEntities = new List(newEntities.Count()); foreach (var item in newEntities) dbEntities.Add(dbSet.Add(item).Entity); context.SaveChanges(); entities.AddRange(dbEntities); return dbEntities; } public async Task> InsertAsync(IEnumerable newEntities, CancellationToken token = default) { var dbSet = context.Set(); var dbEntities = new List(newEntities.Count()); foreach (var item in newEntities) dbEntities.Add(dbSet.Add(item).Entity); await context.SaveChangesAsync(token).ConfigureAwait(false); entities.AddRange(dbEntities); return dbEntities; } } }