基于EFCore的数据Cache实现
作者:互联网
.NetCore 内置缓存加入到EFCore操作中,数据更新或者查询时自动更新缓存。
初步完成逻辑代码编写,尚未经过测试,诸多细节有待完善。地址
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
{
/// <summary>
/// a queue to save the handle,if will be empted when call savechanges().
/// </summary>
private ConcurrentQueue<CacheEntity> CacheQueue { get; set; }
/// <summary>
/// databse context.
/// </summary>
private DbContext Context { get; set; }
/// <summary>
/// netocre inner cache.
/// </summary>
private IMemoryCache Cache { get; set; }
/// <summary>
/// the time of cache's life cycle
/// </summary>
private int ExpirtTime { get; set; } = 60;
/// <summary>
/// entity context.
/// </summary>
/// <param name="context">database context</param>
/// <param name="cache">cache</param>
/// <param name="expirtTime">expirt time,default 60 sencond.</param>
public DefaultContext(DbContext context, IMemoryCache cache, int expirtTime=60)
{
CacheQueue = new ConcurrentQueue<CacheEntity>();
Context = context;
Cache = cache;
ExpirtTime = expirtTime;
}
/// <summary>
/// add entity to database context and add the handle to the queue.
/// <para>it will be excuted when call Savechange().</para>
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
public void Add<TEntity>(TEntity entity)
where TEntity : class
{
bool reesult = Enqueue(entity, CacheHandleEnum.ADD);
if (reesult)
Context.Add(entity);
}
/// <summary>
/// add entity list to database context and add the handle to the queue.
/// <para>it will be excuted when call Savechange().</para>
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entities"></param>
public void AddRange<TEntity>(params TEntity[] entities)
where TEntity : class
{
foreach (var item in entities)
Add(item);
}
/// <summary>
/// remove entity to database context and add the handle to the queue.
/// <para>it will be excuted when call Savechange().</para>
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
public void Remove<TEntity>(TEntity entity)
where TEntity : class
{
bool reesult = Enqueue(entity, CacheHandleEnum.DELETE);
if (reesult)
Context.Remove(entity);
}
/// <summary>
/// remove entity list to database context and add the handle to the queue.
/// <para>it will be excuted when call Savechange().</para>
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entities"></param>
public void RemoveRange<TEntity>(params TEntity[] entities)
where TEntity : class
{
foreach (var item in entities)
Remove(item);
}
/// <summary>
/// update entity to database context and add the handle to the queue.
/// <para>it will be excuted when call Savechange().</para>
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
public void Update<TEntity>(TEntity entity)
where TEntity : class
{
bool reesult = Enqueue(entity, CacheHandleEnum.UPDATE);
if (reesult)
Context.Update(entity);
}
/// <summary>
/// update entity list to database context and add the handle to the queue.
/// <para>it will be excuted when call Savechange().</para>
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entities"></param>
public void UpdateRange<TEntity>(params TEntity[] entities)
where TEntity : class
{
foreach (var item in entities)
Update(item);
}
/// <summary>
/// attach entity to database context add the handle to the queue.
/// <para>it will be excuted when call Savechange().</para>
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entities"></param>
public void Attach<TEntity>(TEntity entity)
where TEntity : class
{
bool reesult = Enqueue(entity, CacheHandleEnum.UPDATE);
if (reesult)
Context.Attach(entity);
}
/// <summary>
/// attach entity list to database context add the handle to the queue.
/// <para>it will be excuted when call Savechange().</para>
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entities"></param>
public void AttachRange<TEntity>(params TEntity[] entities)
where TEntity : class
{
foreach (var item in entities)
Attach(item);
}
/// <summary>
/// update cache and database.
/// <para>update cache at first,if update cache is failed,return false,else commit the changes to database.</para>
/// </summary>
/// <returns></returns>
public bool SaveChanges()
{
bool result = Dequeue();
if (result)
result = Context.SaveChanges() > 0;
return result;
}
/// <summary>
/// single query.
/// <para>find it in the cache first,return if find it,otherwise search it in database by efcore.</para>
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public TEntity Get<TEntity>(string key)
where TEntity : class
{
var result = GetCache<TEntity>();
if (result == null)
result = Context.Find<TEntity>(key);
/*if add it to the cache before back the query result?*/
Enqueue(result, CacheHandleEnum.ADD);
return result;
}
/// <summary>
/// collection query.
/// <para>do not allow fuzzy query</para>
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="keys"></param>
/// <returns></returns>
public List<TEntity> Get<TEntity>(string[] keys)
where TEntity : class
{
var result = new List<TEntity>();
foreach (var item in keys)
result.Add(Get<TEntity>(item));
return result;
}
#region private
#region cache queue
/// <summary>
/// add the handle to the context queue.
/// </summary>
/// <param name="model"></param>
/// <param name="handleEnum"></param>
private bool Enqueue(object model, CacheHandleEnum handleEnum)
{
var key = GetModelKey(model);
var entity = new CacheEntity()
{
ExpiryTime = ExpirtTime,
Handle = handleEnum,
Value = model,
key = key
};
if (CacheQueue.TryPeek(out CacheEntity cacheEntity1))
return false;
else
{
CacheQueue.Enqueue(entity);
return CacheQueue.TryPeek(out CacheEntity cacheEntity2);
}
}
/// <summary>
/// update the changes to cache,and remove it from the cache queue.
/// <para>include add,delete and update.</para>
/// </summary>
/// <returns></returns>
private bool Dequeue()
{
bool check = false;
bool dequeue = CacheQueue.TryDequeue(out CacheEntity cacheEntity);
if (dequeue)
{
switch (cacheEntity.Handle)
{
case CacheHandleEnum.ADD:
check = AddCache(cacheEntity);
break;
case CacheHandleEnum.DELETE:
check = RemoveCache(cacheEntity);
break;
case CacheHandleEnum.UPDATE:
check = RemoveCache(cacheEntity);
if (check)
check = AddCache(cacheEntity);
break;
default:
check = false;
break;
}
}
else
{
check = false;
/*do nothing*/
}
return check;
}
#endregion
#region cache core
/// <summary>
/// add cache
/// </summary>
/// <param name="cacheEntity"></param>
/// <returns></returns>
private bool AddCache(CacheEntity cacheEntity)
{
bool check;
Cache.Set(cacheEntity.key, cacheEntity.Value, new TimeSpan(0, 0, cacheEntity.ExpiryTime));
check = Cache.Get(cacheEntity.key) != null;
return check;
}
/// <summary>
/// remove cache.
/// </summary>
/// <param name="cacheEntity"></param>
/// <returns></returns>
private bool RemoveCache(CacheEntity cacheEntity)
{
bool check;
Cache.Remove(cacheEntity.key);
check = Cache.Get(cacheEntity.key) == null;
return check;
}
/// <summary>
/// update cache.
/// </summary>
/// <param name="cacheEntity"></param>
/// <returns></returns>
private bool UpdateCache(CacheEntity cacheEntity)
{
bool check = RemoveCache(cacheEntity);
if (check)
check = AddCache(cacheEntity);
return check;
}
/// <summary>
/// get cache by key.
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <returns></returns>
private TEntity GetCache<TEntity>()
where TEntity : class
{
string key = GetModelKey(default(TEntity));
Cache.TryGetValue(key, out object value);
return value as TEntity;
}
#endregion
#region other
/// <summary>
/// get the key of a entity.
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
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.Name;
break;
}
}
return key;
}
#endregion
#endregion
}
/// <summary>
/// a entity to handle cache
/// </summary>
public sealed class CacheEntity
{
/// <summary>
/// cache key
/// </summary>
[Key]
public string key { get; set; }
/// <summary>
/// cache value
/// </summary>
public object Value { get; set; }
/// <summary>
/// The lifecycle of caching,seconds.
/// </summary>
public int ExpiryTime { get; set; }
/// <summary>
/// the method will be executed.
/// </summary>
public CacheHandleEnum Handle { get; set; }
}
/// <summary>
/// define the handle of cache
/// </summary>
public enum CacheHandleEnum
{
/// <summary>
/// add cache
/// </summary>
ADD = 1,
/// <summary>
/// delete cache
/// </summary>
DELETE = 2,
/// <summary>
/// update cache
/// </summary>
UPDATE = 3
}
}
标签:基于,Cache,key,check,TEntity,cache,entity,EFCore,public 来源: https://www.cnblogs.com/fuxuyang/p/10778354.html