2021-04-07 18:01:56 +05:00
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace AsbCloudInfrastructure.Services.Cache
|
|
|
|
|
{
|
2021-05-20 14:14:51 +05:00
|
|
|
|
public class CacheTable<TEntity> where TEntity : class
|
2021-04-07 18:01:56 +05:00
|
|
|
|
{
|
|
|
|
|
private readonly DbContext context;
|
2021-05-21 12:30:25 +05:00
|
|
|
|
private (DateTime refreshDate, IEnumerable<object> entities) data;
|
2021-04-23 10:21:25 +05:00
|
|
|
|
private readonly List<TEntity> cached;
|
2021-04-07 18:01:56 +05:00
|
|
|
|
|
2021-05-21 12:30:25 +05:00
|
|
|
|
internal CacheTable(DbContext context, (DateTime refreshDate, IEnumerable<object> entities) data)
|
2021-04-07 18:01:56 +05:00
|
|
|
|
{
|
|
|
|
|
this.context = context;
|
2021-05-21 12:30:25 +05:00
|
|
|
|
this.data = data;
|
|
|
|
|
this.cached = (List<TEntity>)data.entities;
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 10:21:25 +05:00
|
|
|
|
public TEntity this[int index] { get => cached.ElementAt(index); }
|
2021-04-07 18:01:56 +05:00
|
|
|
|
|
|
|
|
|
public int Refresh()
|
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
cached.Clear();
|
|
|
|
|
var dbEntities = context.Set<TEntity>().ToList();
|
|
|
|
|
cached.AddRange(dbEntities);
|
|
|
|
|
data.refreshDate = DateTime.Now;
|
|
|
|
|
return cached.Count;
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<int> RefreshAsync(CancellationToken token = default)
|
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
cached.Clear();
|
|
|
|
|
var dbEntities = await context.Set<TEntity>().ToListAsync(token).ConfigureAwait(false);
|
|
|
|
|
cached.AddRange(dbEntities);
|
|
|
|
|
data.refreshDate = DateTime.Now;
|
|
|
|
|
return cached.Count;
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool CheckRefresh(RefreshMode refreshMode)
|
|
|
|
|
{
|
|
|
|
|
if (refreshMode == RefreshMode.Force)
|
|
|
|
|
{
|
|
|
|
|
Refresh();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 10:21:25 +05:00
|
|
|
|
if ((!cached.Any()) && (refreshMode == RefreshMode.IfResultEmpty))
|
2021-04-07 18:01:56 +05:00
|
|
|
|
{
|
|
|
|
|
Refresh();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<bool> CheckRefreshAsync(RefreshMode refreshMode, CancellationToken token = default)
|
|
|
|
|
{
|
|
|
|
|
if (refreshMode == RefreshMode.Force)
|
|
|
|
|
{
|
|
|
|
|
await RefreshAsync(token);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 10:21:25 +05:00
|
|
|
|
if ((!cached.Any()) && (refreshMode == RefreshMode.IfResultEmpty))
|
2021-04-07 18:01:56 +05:00
|
|
|
|
{
|
|
|
|
|
await RefreshAsync(token);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool Contains(Func<TEntity, bool> predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty)
|
|
|
|
|
=> FirstOrDefault(predicate, refreshMode) != default;
|
|
|
|
|
|
|
|
|
|
public Task<bool> ContainsAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
|
|
|
|
|
=> ContainsAsync(predicate, RefreshMode.IfResultEmpty, token);
|
|
|
|
|
|
|
|
|
|
public async Task<bool> ContainsAsync(Func<TEntity, bool> predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default)
|
|
|
|
|
=> await FirstOrDefaultAsync(predicate, refreshMode, token) != default;
|
|
|
|
|
|
|
|
|
|
public Task<TEntity> FirstOrDefaultAsync(CancellationToken token = default)
|
|
|
|
|
=> FirstOrDefaultAsync(RefreshMode.IfResultEmpty, token);
|
|
|
|
|
|
|
|
|
|
public TEntity FirstOrDefault(RefreshMode refreshMode = RefreshMode.IfResultEmpty)
|
|
|
|
|
{
|
|
|
|
|
bool isUpdated = CheckRefresh(refreshMode);
|
2021-04-23 10:21:25 +05:00
|
|
|
|
var result = cached.FirstOrDefault();
|
2021-04-07 18:01:56 +05:00
|
|
|
|
if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
|
|
|
|
|
{
|
|
|
|
|
Refresh();
|
2021-04-23 10:21:25 +05:00
|
|
|
|
return cached.FirstOrDefault();
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<TEntity> FirstOrDefaultAsync(RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default)
|
|
|
|
|
{
|
|
|
|
|
bool isUpdated = await CheckRefreshAsync(refreshMode, token);
|
2021-04-23 10:21:25 +05:00
|
|
|
|
var result = cached.FirstOrDefault();
|
2021-04-07 18:01:56 +05:00
|
|
|
|
if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
|
|
|
|
|
{
|
|
|
|
|
await RefreshAsync(token);
|
2021-04-23 10:21:25 +05:00
|
|
|
|
return cached.FirstOrDefault();
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<TEntity> FirstOrDefaultAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
|
|
|
|
|
=> FirstOrDefaultAsync(predicate, RefreshMode.IfResultEmpty, token);
|
|
|
|
|
|
|
|
|
|
public TEntity FirstOrDefault(Func<TEntity, bool> predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty)
|
|
|
|
|
{
|
|
|
|
|
bool isUpdated = CheckRefresh(refreshMode);
|
2021-04-23 10:21:25 +05:00
|
|
|
|
var result = cached.FirstOrDefault(predicate);
|
2021-04-07 18:01:56 +05:00
|
|
|
|
if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
|
|
|
|
|
{
|
|
|
|
|
Refresh();
|
2021-04-23 10:21:25 +05:00
|
|
|
|
return cached.FirstOrDefault(predicate);
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<TEntity> FirstOrDefaultAsync(Func<TEntity, bool> predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default)
|
|
|
|
|
{
|
|
|
|
|
bool isUpdated = await CheckRefreshAsync(refreshMode, token);
|
2021-04-23 10:21:25 +05:00
|
|
|
|
var result = cached.FirstOrDefault(predicate);
|
2021-04-07 18:01:56 +05:00
|
|
|
|
if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
|
|
|
|
|
{
|
|
|
|
|
await RefreshAsync(token);
|
2021-04-23 10:21:25 +05:00
|
|
|
|
return cached.FirstOrDefault(predicate);
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<IEnumerable<TEntity>> SelectAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
|
|
|
|
|
=> SelectAsync(predicate, RefreshMode.IfResultEmpty, token);
|
|
|
|
|
|
|
|
|
|
public IEnumerable<TEntity> Select(Func<TEntity, bool> predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty)
|
|
|
|
|
{
|
|
|
|
|
bool isUpdated = CheckRefresh(refreshMode);
|
2021-04-23 10:21:25 +05:00
|
|
|
|
var result = cached.Where(predicate);
|
2021-04-07 18:01:56 +05:00
|
|
|
|
if (!result.Any() && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
|
|
|
|
|
{
|
|
|
|
|
Refresh();
|
2021-04-23 10:21:25 +05:00
|
|
|
|
return cached.Where(predicate);
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<IEnumerable<TEntity>> SelectAsync(Func<TEntity, bool> predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default)
|
|
|
|
|
{
|
|
|
|
|
bool isUpdated = await CheckRefreshAsync(refreshMode, token);
|
2021-04-23 10:21:25 +05:00
|
|
|
|
var result = cached.Where(predicate);
|
2021-04-07 18:01:56 +05:00
|
|
|
|
if (!result.Any() && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
|
|
|
|
|
{
|
|
|
|
|
await RefreshAsync(token);
|
2021-04-23 10:21:25 +05:00
|
|
|
|
return cached.Where(predicate);
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 09:15:10 +05:00
|
|
|
|
public IEnumerable<TEntity> Mutate(Func<TEntity, bool> predicate, Action<TEntity> mutation)
|
2021-04-07 18:01:56 +05:00
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
var dbSet = context.Set<TEntity>();
|
|
|
|
|
var dbEntities = dbSet.Where(predicate);
|
|
|
|
|
if (dbEntities.Any())
|
2021-04-07 18:01:56 +05:00
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
foreach (var dbEntity in dbEntities)
|
|
|
|
|
mutation(dbEntity);
|
|
|
|
|
context.SaveChanges();
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
2021-07-16 09:15:10 +05:00
|
|
|
|
cached.RemoveAll(e => predicate(e));
|
|
|
|
|
cached.AddRange(dbEntities);
|
|
|
|
|
return dbEntities;
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 09:15:10 +05:00
|
|
|
|
public async Task<IEnumerable<TEntity>> MutateAsync(Func<TEntity, bool> predicate, Action<TEntity> mutation, CancellationToken token = default)
|
2021-04-23 10:21:25 +05:00
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
var dbSet = context.Set<TEntity>();
|
|
|
|
|
var dbEntities = dbSet.Where(predicate);
|
|
|
|
|
if (dbEntities.Any())
|
2021-04-23 10:21:25 +05:00
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
foreach (var dbEntity in dbEntities)
|
|
|
|
|
mutation(dbEntity);
|
|
|
|
|
await context.SaveChangesAsync(token).ConfigureAwait(false);
|
2021-04-23 10:21:25 +05:00
|
|
|
|
}
|
2021-07-16 09:15:10 +05:00
|
|
|
|
cached.RemoveAll(e => predicate(e));
|
|
|
|
|
cached.AddRange(dbEntities);
|
|
|
|
|
return dbEntities;
|
2021-04-23 10:21:25 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-21 17:42:18 +05:00
|
|
|
|
public TEntity Upsert(TEntity entity)
|
2021-04-23 10:21:25 +05:00
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
var dbSet = context.Set<TEntity>();
|
|
|
|
|
var updated = dbSet.Update(entity);
|
|
|
|
|
context.SaveChanges();
|
|
|
|
|
Refresh();
|
|
|
|
|
return updated.Entity;
|
2021-05-21 17:42:18 +05:00
|
|
|
|
}
|
2021-04-23 10:21:25 +05:00
|
|
|
|
|
2021-05-21 17:42:18 +05:00
|
|
|
|
public async Task<TEntity> UpsertAsync(TEntity entity, CancellationToken token = default)
|
2021-04-23 10:21:25 +05:00
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
var dbSet = context.Set<TEntity>();
|
2021-07-20 12:28:56 +05:00
|
|
|
|
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> updated;
|
|
|
|
|
if (dbSet.Contains(entity))
|
|
|
|
|
updated = dbSet.Update(entity);
|
|
|
|
|
else
|
|
|
|
|
updated = dbSet.Add(entity);
|
2021-07-16 09:15:10 +05:00
|
|
|
|
await context.SaveChangesAsync(token).ConfigureAwait(false);
|
|
|
|
|
await RefreshAsync(token).ConfigureAwait(false);
|
|
|
|
|
return updated.Entity;
|
2021-05-21 17:42:18 +05:00
|
|
|
|
}
|
2021-04-23 10:21:25 +05:00
|
|
|
|
|
2021-05-21 17:42:18 +05:00
|
|
|
|
public IEnumerable<TEntity> Upsert(IEnumerable<TEntity> entities)
|
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
var dbSet = context.Set<TEntity>();
|
|
|
|
|
var upsertedEntries = new List<TEntity>(entities.Count());
|
|
|
|
|
foreach (var entity in entities)
|
2021-07-20 12:28:56 +05:00
|
|
|
|
{
|
|
|
|
|
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> updated;
|
|
|
|
|
if (dbSet.Contains(entity))
|
|
|
|
|
updated = dbSet.Update(entity);
|
|
|
|
|
else
|
|
|
|
|
updated = dbSet.Add(entity);
|
|
|
|
|
upsertedEntries.Add(updated.Entity);
|
|
|
|
|
}
|
2021-07-16 09:15:10 +05:00
|
|
|
|
context.SaveChanges();
|
|
|
|
|
Refresh();
|
|
|
|
|
return upsertedEntries;
|
2021-04-23 10:21:25 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<IEnumerable<TEntity>> UpsertAsync(IEnumerable<TEntity> entities, CancellationToken token = default)
|
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
var dbSet = context.Set<TEntity>();
|
|
|
|
|
var upsertedEntries = new List<TEntity>(entities.Count());
|
|
|
|
|
foreach (var entity in entities)
|
2021-07-20 12:28:56 +05:00
|
|
|
|
{
|
|
|
|
|
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> updated;
|
|
|
|
|
if (dbSet.Contains(entity))
|
|
|
|
|
updated = dbSet.Update(entity);
|
|
|
|
|
else
|
|
|
|
|
updated = dbSet.Add(entity);
|
|
|
|
|
upsertedEntries.Add(updated.Entity);
|
|
|
|
|
}
|
2021-07-16 09:15:10 +05:00
|
|
|
|
await context.SaveChangesAsync(token).ConfigureAwait(false);
|
|
|
|
|
await RefreshAsync(token).ConfigureAwait(false);
|
|
|
|
|
return upsertedEntries;
|
2021-04-23 10:21:25 +05:00
|
|
|
|
}
|
2021-07-16 09:15:10 +05:00
|
|
|
|
|
2021-04-07 18:01:56 +05:00
|
|
|
|
public void Remove(Func<TEntity, bool> predicate)
|
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
var dbSet = context.Set<TEntity>();
|
|
|
|
|
cached.RemoveAll(e => predicate(e));
|
|
|
|
|
dbSet.RemoveRange(dbSet.Where(predicate));
|
|
|
|
|
context.SaveChanges();
|
|
|
|
|
return;
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task RemoveAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
|
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
var dbSet = context.Set<TEntity>();
|
|
|
|
|
cached.RemoveAll(e => predicate(e));
|
|
|
|
|
dbSet.RemoveRange(dbSet.Where(predicate));
|
|
|
|
|
await context.SaveChangesAsync(token).ConfigureAwait(false);
|
|
|
|
|
return;
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public TEntity Insert(TEntity entity)
|
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
var dbSet = context.Set<TEntity>();
|
|
|
|
|
var dbEntity = dbSet.Add(entity).Entity;
|
|
|
|
|
context.SaveChanges();
|
|
|
|
|
cached.Add(dbEntity);
|
|
|
|
|
return dbEntity;
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<TEntity> InsertAsync(TEntity entity, CancellationToken token = default)
|
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
var dbSet = context.Set<TEntity>();
|
|
|
|
|
var dbEntity = dbSet.Add(entity).Entity;
|
|
|
|
|
await context.SaveChangesAsync(token).ConfigureAwait(false);
|
|
|
|
|
cached.Add(dbEntity);
|
|
|
|
|
return dbEntity;
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IEnumerable<TEntity> Insert(IEnumerable<TEntity> newEntities)
|
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
var dbSet = context.Set<TEntity>();
|
|
|
|
|
var dbEntities = new List<TEntity>(newEntities.Count());
|
|
|
|
|
foreach (var item in newEntities)
|
|
|
|
|
dbEntities.Add(dbSet.Add(item).Entity);
|
|
|
|
|
context.SaveChanges();
|
|
|
|
|
cached.AddRange(dbEntities);
|
|
|
|
|
return dbEntities;
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<IEnumerable<TEntity>> InsertAsync(IEnumerable<TEntity> newEntities, CancellationToken token = default)
|
|
|
|
|
{
|
2021-07-16 09:15:10 +05:00
|
|
|
|
var dbSet = context.Set<TEntity>();
|
|
|
|
|
var dbEntities = new List<TEntity>(newEntities.Count());
|
|
|
|
|
foreach (var item in newEntities)
|
|
|
|
|
dbEntities.Add(dbSet.Add(item).Entity);
|
|
|
|
|
await context.SaveChangesAsync(token).ConfigureAwait(false);
|
|
|
|
|
cached.AddRange(dbEntities);
|
|
|
|
|
return dbEntities;
|
2021-05-21 17:42:18 +05:00
|
|
|
|
}
|
2021-04-07 18:01:56 +05:00
|
|
|
|
}
|
|
|
|
|
}
|