EFCoreベースのデータCache実装
11689 ワード
.NetCore内蔵キャッシュはEFCore操作に組み込まれ、データの更新やクエリー時に自動的にキャッシュが更新されます.githubアドレス
2019-04-27論理コードの作成を初歩的に完了し、まだテストされていないため、多くの詳細が改善されなければならない。
2019-04-28簡単な機能テストと一部のエラーロジック修正。
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace FXY_NetCore_DbContext
{
public class DefaultContext
{
///
/// a queue to save the handle,if will be empted when call savechanges().
///
private ConcurrentQueue CacheQueue { get; set; }
///
/// databse context.
///
private DbContext Context { get; set; }
///
/// netocre inner cache.
///
private IMemoryCache Cache { get; set; }
///
/// the time of cache's life cycle
///
private int ExpirtTime { get; set; } = 10;
///
/// entity context.
///
/// database context
/// cache
/// expirt time,default 60 sencond.
public DefaultContext(DbContext context, IMemoryCache cache, int expirtTime = 10)
{
CacheQueue = new ConcurrentQueue();
Context = context;
Cache = cache;
ExpirtTime = expirtTime;
}
///
/// add entity to database context and add the handle to the queue.
/// it will be excuted when call Savechange().
///
///
///
public void Add(TEntity entity)
where TEntity : class, new()
{
Context.Add(entity);
}
///
/// add entity list to database context and add the handle to the queue.
/// it will be excuted when call Savechange().
///
///
///
public void AddRange(params TEntity[] entities)
where TEntity : class, new()
{
foreach (var item in entities)
Add(item);
}
///
/// remove entity to database context and add the handle to the queue.
/// it will be excuted when call Savechange().
///
///
///
public void Remove(TEntity entity)
where TEntity : class, new()
{
bool reesult = Enqueue(entity);
if (reesult)
Context.Remove(entity);
}
///
/// remove entity list to database context and add the handle to the queue.
/// it will be excuted when call Savechange().
///
///
///
public void RemoveRange(params TEntity[] entities)
where TEntity : class, new()
{
foreach (var item in entities)
Remove(item);
}
///
/// update entity to database context and add the handle to the queue.
/// it will be excuted when call Savechange().
///
///
///
public void Update(TEntity entity)
where TEntity : class, new()
{
bool reesult = Enqueue(entity);
if (reesult)
Context.Update(entity);
}
///
/// update entity list to database context and add the handle to the queue.
/// it will be excuted when call Savechange().
///
///
///
public void UpdateRange(params TEntity[] entities)
where TEntity : class, new()
{
foreach (var item in entities)
Update(item);
}
///
/// attach entity to database context add the handle to the queue.
/// it will be excuted when call Savechange().
///
///
///
public void Attach(TEntity entity)
where TEntity : class, new()
{
bool reesult = Enqueue(entity);
if (reesult)
Context.Attach(entity);
}
///
/// attach entity list to database context add the handle to the queue.
/// it will be excuted when call Savechange().
///
///
///
public void AttachRange(params TEntity[] entities)
where TEntity : class, new()
{
foreach (var item in entities)
Attach(item);
}
///
/// update cache and database.
/// update cache at first,if update cache is failed,return false,else commit the changes to database.
///
///
public bool SaveChanges()
{
bool result = Dequeue();
if (result)
result = Context.SaveChanges() > 0;
return result;
}
///
/// single query.
/// find it in the cache first,return if find it,otherwise search it in database by efcore.
///
///
///
///
public TEntity Get(string key)
where TEntity : class, new()
{
var result = GetCache(key);
if (result == null)
{
result = Context.Find(key);
var cacheEntity = GetCacheEntity(result);
AddCache(cacheEntity);
}
else
{
var cacheEntity = GetCacheEntity(result);
UpdateCache(cacheEntity);
}
return result;
}
///
/// collection query.
/// do not allow fuzzy query
///
///
///
///
public List Get(string[] keys)
where TEntity : class, new()
{
var result = new List();
foreach (var item in keys)
result.Add(Get(item));
return result;
}
#region private
#region cache queue
///
/// add the handle to the context queue.
///
///
///
private bool Enqueue(object model)
{
CacheEntity entity = GetCacheEntity(model);
if (CacheQueue.TryPeek(out CacheEntity cacheEntity1))
return false;
else
{
CacheQueue.Enqueue(entity);
return CacheQueue.TryPeek(out CacheEntity cacheEntity2);
}
}
///
/// update the changes to cache,and remove it from the cache queue.
/// include add,delete and update.
///
///
private bool Dequeue()
{
bool check = false;
bool dequeue = CacheQueue.TryDequeue(out CacheEntity cacheEntity);
if (dequeue)
check = RemoveCache(cacheEntity);
else
check = false;
return check;
}
#endregion
#region cache core
///
/// add cache
///
///
///
private bool AddCache(CacheEntity cacheEntity)
{
bool check;
Cache.Set(cacheEntity.key, cacheEntity.Value, new TimeSpan(0, 0, ExpirtTime));
check = Cache.Get(cacheEntity.key) != null;
return check;
}
///
/// remove cache.
///
///
///
private bool RemoveCache(CacheEntity cacheEntity)
{
bool check;
Cache.Remove(cacheEntity.key);
check = Cache.Get(cacheEntity.key) == null;
return check;
}
///
/// update cache.
///
///
///
private bool UpdateCache(CacheEntity cacheEntity)
{
bool check = RemoveCache(cacheEntity);
if (check)
check = AddCache(cacheEntity);
return check;
}
///
/// get cache by key.
///
///
///
private TEntity GetCache(string key)
where TEntity : class, new()
{
Cache.TryGetValue(key, out object value);
return value as TEntity;
}
#endregion
#region other
///
/// get private cache entity.
///
///
///
///
private CacheEntity GetCacheEntity(object model)
{
var key = GetModelKey(model);
var entity = new CacheEntity()
{
Value = model,
key = key
};
return entity;
}
///
/// get the key of a entity.
///
///
///
private string GetModelKey(object model)
{
string key = "";
var type = model.GetType().GetProperties();
foreach (var item in type)
{
if (item.GetCustomAttributes(typeof(KeyAttribute), true).Length > 0)
{
key = item.GetValue(model).ToString();
break;
}
}
return key;
}
#endregion
#endregion
}
///
/// a entity to handle cache
///
public sealed class CacheEntity
{
///
/// cache key
///
[Key]
public string key { get; set; }
///
/// cache value
///
public object Value { get; set; }
}
}