DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/Cache/CacheTable.cs

325 lines
12 KiB
C#
Raw Normal View History

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
{
public class CacheTable<TEntity> where TEntity : class
2021-04-07 18:01:56 +05:00
{
private readonly DbContext context;
private (DateTime refreshDate, IEnumerable<object> entities) data;
2021-04-23 10:21:25 +05:00
private readonly List<TEntity> cached;
private readonly DbSet<TEntity> dbSet;
private readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
2021-04-07 18:01:56 +05:00
internal CacheTable(DbContext context, (DateTime refreshDate, IEnumerable<object> entities) data)
2021-04-07 18:01:56 +05:00
{
this.context = context;
this.data = data;
this.cached = (List<TEntity>)data.entities;
dbSet = context.Set<TEntity>();
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()
{
if (cached.Any())
{
semaphore.Wait();
2021-07-29 12:36:29 +05:00
cached.Clear();
}
2021-08-10 16:35:31 +05:00
var dbEntities = context.Set<TEntity>().AsNoTracking().ToList();
2021-07-16 09:15:10 +05:00
cached.AddRange(dbEntities);
data.refreshDate = DateTime.Now;
2021-07-21 15:29:19 +05:00
return cached.Count;
2021-04-07 18:01:56 +05:00
}
public async Task<int> RefreshAsync(CancellationToken token = default)
{
2021-07-29 12:36:29 +05:00
if (cached.Any())
{
await semaphore.WaitAsync(token).ConfigureAwait(true);
cached.Clear();
}
2021-08-10 16:35:31 +05:00
var dbEntities = await context.Set<TEntity>().AsNoTracking().ToListAsync(token).ConfigureAwait(false);
2021-07-16 09:15:10 +05:00
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;
}
2021-08-27 17:55:22 +05:00
public Task<IEnumerable<TEntity>> WhereAsync(CancellationToken token = default)
=> WhereAsync(default, RefreshMode.IfResultEmpty, token);
public Task<IEnumerable<TEntity>> WhereAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
=> WhereAsync(predicate, RefreshMode.IfResultEmpty, token);
2021-04-07 18:01:56 +05:00
public IEnumerable<TEntity> Where(Func<TEntity, bool> predicate = default, RefreshMode refreshMode = RefreshMode.IfResultEmpty)
2021-04-07 18:01:56 +05:00
{
bool isUpdated = CheckRefresh(refreshMode);
var result = (predicate != default)
? cached.Where(predicate)
: cached;
2021-04-07 18:01:56 +05:00
if (!result.Any() && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
{
Refresh();
result = (predicate != default)
? cached.Where(predicate)
: cached;
2021-04-07 18:01:56 +05:00
}
return result;
}
public async Task<IEnumerable<TEntity>> WhereAsync(Func<TEntity, bool> predicate = default,
RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default)
2021-04-07 18:01:56 +05:00
{
bool isUpdated = await CheckRefreshAsync(refreshMode, token);
var result = (predicate != default)
? cached.Where(predicate)
: cached;
2021-04-07 18:01:56 +05:00
if (!result.Any() && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
{
await RefreshAsync(token);
result = (predicate != default)
? cached.Where(predicate)
: cached;
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 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 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
}
public TEntity Upsert(TEntity entity)
2021-04-23 10:21:25 +05:00
{
2021-07-16 09:15:10 +05:00
var updated = dbSet.Update(entity);
context.SaveChanges();
Refresh();
return updated.Entity;
}
2021-04-23 10:21:25 +05:00
public async Task<TEntity> UpsertAsync(TEntity entity, CancellationToken token = default)
2021-04-23 10:21:25 +05:00
{
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-04-23 10:21:25 +05:00
public IEnumerable<TEntity> Upsert(IEnumerable<TEntity> entities)
{
2021-07-16 09:15:10 +05:00
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;
2021-08-10 16:35:31 +05:00
if (dbSet.Contains(entity)) // TODO: это очень ммедленно
2021-07-20 12:28:56 +05:00
updated = dbSet.Update(entity);
else
updated = dbSet.Add(entity);
upsertedEntries.Add(updated.Entity);
2021-07-21 15:29:19 +05:00
}
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 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
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
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 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 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 dbEntities = new List<TEntity>(newEntities.Count());
foreach (var item in newEntities)
dbEntities.Add(dbSet.Add(item).Entity);
context.SaveChanges();
cached.AddRange(dbEntities);
2021-07-21 15:29:19 +05:00
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 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-04-07 18:01:56 +05:00
}
}