CS2-13: Добавлена потокобезопасность для данных в CaсheTable

This commit is contained in:
KharchenkoVV 2021-05-21 17:42:18 +05:00
parent 7b00cedb47
commit ae85cdedd5

View File

@ -12,6 +12,7 @@ namespace AsbCloudInfrastructure.Services.Cache
private readonly DbContext context; private readonly DbContext context;
private (DateTime refreshDate, IEnumerable<object> entities) data; private (DateTime refreshDate, IEnumerable<object> entities) data;
private readonly List<TEntity> cached; private readonly List<TEntity> cached;
private readonly ReaderWriterLockSlim cacheLocker = new ReaderWriterLockSlim();
internal CacheTable(DbContext context, (DateTime refreshDate, IEnumerable<object> entities) data) internal CacheTable(DbContext context, (DateTime refreshDate, IEnumerable<object> entities) data)
{ {
@ -24,20 +25,36 @@ namespace AsbCloudInfrastructure.Services.Cache
public int Refresh() public int Refresh()
{ {
cached.Clear(); cacheLocker.EnterWriteLock();
var dbEntities = context.Set<TEntity>().ToList(); try
cached.AddRange(dbEntities); {
data.refreshDate = DateTime.Now; cached.Clear();
return cached.Count; var dbEntities = context.Set<TEntity>().ToList();
cached.AddRange(dbEntities);
data.refreshDate = DateTime.Now;
return cached.Count;
}
finally
{
cacheLocker.ExitWriteLock();
}
} }
public async Task<int> RefreshAsync(CancellationToken token = default) public async Task<int> RefreshAsync(CancellationToken token = default)
{ {
cached.Clear(); cacheLocker.EnterWriteLock();
var dbEntities = await context.Set<TEntity>().ToListAsync(token).ConfigureAwait(false); try
cached.AddRange(dbEntities); {
data.refreshDate = DateTime.Now; cached.Clear();
return cached.Count; var dbEntities = await context.Set<TEntity>().ToListAsync(token).ConfigureAwait(false);
cached.AddRange(dbEntities);
data.refreshDate = DateTime.Now;
return cached.Count;
}
finally
{
cacheLocker.ExitWriteLock();
}
} }
private bool CheckRefresh(RefreshMode refreshMode) private bool CheckRefresh(RefreshMode refreshMode)
@ -184,193 +201,300 @@ namespace AsbCloudInfrastructure.Services.Cache
public IEnumerable<TEntity> Update(Func<TEntity, bool> predicate, Action<TEntity> mutation) public IEnumerable<TEntity> Update(Func<TEntity, bool> predicate, Action<TEntity> mutation)
{ {
var dbSet = context.Set<TEntity>(); cacheLocker.EnterWriteLock();
var dbEntities = dbSet.Where(predicate);
if (dbEntities.Any()) try
{ {
foreach (var dbEntity in dbEntities) var dbSet = context.Set<TEntity>();
mutation(dbEntity); var dbEntities = dbSet.Where(predicate);
context.SaveChanges(); if (dbEntities.Any())
{
foreach (var dbEntity in dbEntities)
mutation(dbEntity);
context.SaveChanges();
}
cached.RemoveAll(e => predicate(e));
cached.AddRange(dbEntities);
return dbEntities;
}
finally
{
cacheLocker.ExitWriteLock();
} }
cached.RemoveAll(e => predicate(e));
cached.AddRange(dbEntities);
return dbEntities;
} }
public async Task<IEnumerable<TEntity>> UpdateAsync(Func<TEntity, bool> predicate, Action<TEntity> mutation, CancellationToken token = default) public async Task<IEnumerable<TEntity>> UpdateAsync(Func<TEntity, bool> predicate, Action<TEntity> mutation, CancellationToken token = default)
{ {
var dbSet = context.Set<TEntity>(); cacheLocker.EnterWriteLock();
var dbEntities = dbSet.Where(predicate);
if (dbEntities.Any()) try
{ {
foreach (var dbEntity in dbEntities) var dbSet = context.Set<TEntity>();
mutation(dbEntity); var dbEntities = dbSet.Where(predicate);
await context.SaveChangesAsync(token).ConfigureAwait(false); if (dbEntities.Any())
{
foreach (var dbEntity in dbEntities)
mutation(dbEntity);
await context.SaveChangesAsync(token).ConfigureAwait(false);
}
cached.RemoveAll(e => predicate(e));
cached.AddRange(dbEntities);
return dbEntities;
}
finally
{
cacheLocker.ExitWriteLock();
} }
cached.RemoveAll(e => predicate(e));
cached.AddRange(dbEntities);
return dbEntities;
} }
public TEntity Upsert(TEntity entity) public TEntity Upsert(TEntity entity)
{ {
var dbSet = context.Set<TEntity>(); cacheLocker.EnterWriteLock();
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> entityEntry;
if (cached.Contains(entity)) try
{ {
entityEntry = dbSet.Update(entity); var dbSet = context.Set<TEntity>();
cached.Remove(entity); Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> entityEntry;
if (cached.Contains(entity))
{
entityEntry = dbSet.Update(entity);
cached.Remove(entity);
}
else
{
entityEntry = dbSet.Add(entity);
}
context.SaveChanges();
cached.Add(entityEntry.Entity);
return entityEntry.Entity;
} }
else finally
{ {
entityEntry = dbSet.Add(entity); cacheLocker.ExitWriteLock();
} }
context.SaveChanges();
cached.Add(entityEntry.Entity);
return entityEntry.Entity;
} }
public async Task<TEntity> UpsertAsync(TEntity entity, CancellationToken token = default) public async Task<TEntity> UpsertAsync(TEntity entity, CancellationToken token = default)
{ {
var dbSet = context.Set<TEntity>(); cacheLocker.EnterWriteLock();
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> entityEntry;
if (cached.Contains(entity)) try
{ {
entityEntry = dbSet.Update(entity); var dbSet = context.Set<TEntity>();
cached.Remove(entity); Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> entityEntry;
if (cached.Contains(entity))
{
entityEntry = dbSet.Update(entity);
cached.Remove(entity);
}
else
{
entityEntry = dbSet.Add(entity);
}
await context.SaveChangesAsync(token).ConfigureAwait(false);
cached.Add(entityEntry.Entity);
return entityEntry.Entity;
} }
else finally
{ {
entityEntry = dbSet.Add(entity); cacheLocker.ExitWriteLock();
} }
await context.SaveChangesAsync(token).ConfigureAwait(false);
cached.Add(entityEntry.Entity);
return entityEntry.Entity;
} }
public IEnumerable<TEntity> Upsert(IEnumerable<TEntity> entities) public IEnumerable<TEntity> Upsert(IEnumerable<TEntity> entities)
{ {
var dbSet = context.Set<TEntity>(); cacheLocker.EnterWriteLock();
var upsertedEntries = new List<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity>>(entities.Count()); try
foreach (var entity in entities)
{ {
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> entityEntry; var dbSet = context.Set<TEntity>();
if (cached.Contains(entity))
var upsertedEntries = new List<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity>>(entities.Count());
foreach (var entity in entities)
{ {
entityEntry = dbSet.Update(entity); Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> entityEntry;
cached.Remove(entity); if (cached.Contains(entity))
{
entityEntry = dbSet.Update(entity);
cached.Remove(entity);
}
else
{
entityEntry = dbSet.Add(entity);
}
upsertedEntries.Add(entityEntry);
} }
else
{ context.SaveChanges();
entityEntry = dbSet.Add(entity);
} var upserted = upsertedEntries.Select(e => e.Entity);
upsertedEntries.Add(entityEntry);
cached.AddRange(upserted);
return upserted;
}
finally
{
cacheLocker.ExitWriteLock();
} }
context.SaveChanges();
var upserted = upsertedEntries.Select(e => e.Entity);
cached.AddRange(upserted);
return upserted;
} }
public async Task<IEnumerable<TEntity>> UpsertAsync(IEnumerable<TEntity> entities, CancellationToken token = default) public async Task<IEnumerable<TEntity>> UpsertAsync(IEnumerable<TEntity> entities, CancellationToken token = default)
{ {
var dbSet = context.Set<TEntity>(); cacheLocker.EnterWriteLock();
var upsertedEntries = new List<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity>>(entities.Count()); try
foreach (var entity in entities)
{ {
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> entityEntry; var dbSet = context.Set<TEntity>();
if (cached.Contains(entity))
var upsertedEntries = new List<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity>>(entities.Count());
foreach (var entity in entities)
{ {
entityEntry = dbSet.Update(entity); Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> entityEntry;
cached.Remove(entity); if (cached.Contains(entity))
{
entityEntry = dbSet.Update(entity);
cached.Remove(entity);
}
else
{
entityEntry = dbSet.Add(entity);
}
upsertedEntries.Add(entityEntry);
} }
else
{ await context.SaveChangesAsync(token).ConfigureAwait(false);
entityEntry = dbSet.Add(entity);
} var upserted = upsertedEntries.Select(e => e.Entity);
upsertedEntries.Add(entityEntry);
cached.AddRange(upserted);
return upserted;
}
finally
{
cacheLocker.ExitWriteLock();
} }
await context.SaveChangesAsync(token).ConfigureAwait(false);
var upserted = upsertedEntries.Select(e => e.Entity);
cached.AddRange(upserted);
return upserted;
} }
public void Remove(Func<TEntity, bool> predicate) public void Remove(Func<TEntity, bool> predicate)
{ {
var dbSet = context.Set<TEntity>(); cacheLocker.EnterWriteLock();
cached.RemoveAll(e => predicate(e));
dbSet.RemoveRange(dbSet.Where(predicate)); try
context.SaveChanges(); {
return; var dbSet = context.Set<TEntity>();
cached.RemoveAll(e => predicate(e));
dbSet.RemoveRange(dbSet.Where(predicate));
context.SaveChanges();
return;
}
finally
{
cacheLocker.ExitWriteLock();
}
} }
public async Task RemoveAsync(Func<TEntity, bool> predicate, CancellationToken token = default) public async Task RemoveAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
{ {
var dbSet = context.Set<TEntity>(); cacheLocker.EnterWriteLock();
cached.RemoveAll(e => predicate(e));
dbSet.RemoveRange(dbSet.Where(predicate)); try
await context.SaveChangesAsync(token).ConfigureAwait(false); {
return; var dbSet = context.Set<TEntity>();
cached.RemoveAll(e => predicate(e));
dbSet.RemoveRange(dbSet.Where(predicate));
await context.SaveChangesAsync(token).ConfigureAwait(false);
return;
}
finally
{
cacheLocker.ExitWriteLock();
}
} }
public TEntity Insert(TEntity entity) public TEntity Insert(TEntity entity)
{ {
var dbSet = context.Set<TEntity>(); cacheLocker.EnterWriteLock();
var dbEntity = dbSet.Add(entity).Entity;
context.SaveChanges(); try
cached.Add(dbEntity); {
return dbEntity; var dbSet = context.Set<TEntity>();
var dbEntity = dbSet.Add(entity).Entity;
context.SaveChanges();
cached.Add(dbEntity);
return dbEntity;
}
finally
{
cacheLocker.ExitWriteLock();
}
} }
public async Task<TEntity> InsertAsync(TEntity entity, CancellationToken token = default) public async Task<TEntity> InsertAsync(TEntity entity, CancellationToken token = default)
{ {
var dbSet = context.Set<TEntity>(); cacheLocker.EnterWriteLock();
var dbEntity = dbSet.Add(entity).Entity;
await context.SaveChangesAsync(token).ConfigureAwait(false); try
cached.Add(dbEntity); {
return dbEntity; var dbSet = context.Set<TEntity>();
var dbEntity = dbSet.Add(entity).Entity;
await context.SaveChangesAsync(token).ConfigureAwait(false);
cached.Add(dbEntity);
return dbEntity;
}
finally
{
cacheLocker.ExitWriteLock();
}
} }
public IEnumerable<TEntity> Insert(IEnumerable<TEntity> newEntities) public IEnumerable<TEntity> Insert(IEnumerable<TEntity> newEntities)
{ {
var dbSet = context.Set<TEntity>(); cacheLocker.EnterWriteLock();
var dbEntities = new List<TEntity>(newEntities.Count());
foreach (var item in newEntities) try
dbEntities.Add(dbSet.Add(item).Entity); {
context.SaveChanges(); var dbSet = context.Set<TEntity>();
cached.AddRange(dbEntities); var dbEntities = new List<TEntity>(newEntities.Count());
return dbEntities; foreach (var item in newEntities)
dbEntities.Add(dbSet.Add(item).Entity);
context.SaveChanges();
cached.AddRange(dbEntities);
return dbEntities;
}
finally
{
cacheLocker.ExitWriteLock();
}
} }
public async Task<IEnumerable<TEntity>> InsertAsync(IEnumerable<TEntity> newEntities, CancellationToken token = default) public async Task<IEnumerable<TEntity>> InsertAsync(IEnumerable<TEntity> newEntities, CancellationToken token = default)
{ {
var dbSet = context.Set<TEntity>(); cacheLocker.EnterWriteLock();
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;
}
try
{
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;
}
finally
{
cacheLocker.ExitWriteLock();
}
}
} }
} }