forked from ddrilling/AsbCloudServer
CS2-13: Добавлена потокобезопасность для данных в CaсheTable
This commit is contained in:
parent
7b00cedb47
commit
ae85cdedd5
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user