212 lines
6.0 KiB
C#
212 lines
6.0 KiB
C#
using System.Linq.Expressions;
|
|
using YLErp.Abstract;
|
|
|
|
namespace YLErp.Modules.DataCacheModule
|
|
{
|
|
/// <summary>
|
|
/// 通用数据源抽象类
|
|
/// </summary>
|
|
abstract class GenericeCachedDataSource<TData> : IDataUpdater, IDataSource, IDataSource<TData>, IDataSourceEvent, IJsonSerializable
|
|
where TData : class, IDataTraceV2, IDataEntity
|
|
{
|
|
protected int _maxId = -1;
|
|
protected bool _clonable;
|
|
protected readonly Dictionary<int, TData> _dic;
|
|
protected DateTime _lastUptime;
|
|
|
|
public event EventHandler DataSourceUpdated;
|
|
|
|
protected GenericeCachedDataSource()
|
|
{
|
|
_dic = new Dictionary<int, TData>();
|
|
_clonable = typeof(TData).GetInterface(typeof(IClonable<TData>).Name) != null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 数据条数
|
|
/// </summary>
|
|
public int Count => _dic.Count;
|
|
|
|
public abstract string TableName { get; }
|
|
|
|
/// <summary>
|
|
/// 获取数据
|
|
/// </summary>
|
|
public IQueryable<TData> AsQueryable(Expression<Func<TData, bool>> predicate = null)
|
|
{
|
|
lock (this)
|
|
{
|
|
if (_dic.Count < 1)
|
|
{
|
|
return Enumerable.Empty<TData>().AsQueryable();
|
|
}
|
|
|
|
var query = _dic.Values.AsQueryable();
|
|
|
|
if (predicate != null)
|
|
{
|
|
query = query.Where(predicate);
|
|
}
|
|
|
|
if (_clonable)
|
|
{
|
|
return new DataCacheQueryable<TData>(query);
|
|
}
|
|
|
|
return query;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新数据源
|
|
/// </summary>
|
|
public virtual void UpdateData(IEnumerable<string> updateKeyIds)
|
|
{
|
|
lock (_dic)
|
|
{
|
|
InnerUpdateData(updateKeyIds);
|
|
}
|
|
}
|
|
|
|
private void InnerUpdateData(IEnumerable<string> updateKeyIds)
|
|
{
|
|
using (var db = CreateDbContext())
|
|
{
|
|
var table = db.Set<TData>().AsNoTracking();
|
|
|
|
var minId = _maxId;
|
|
var maxId = table.Max(n => (int?)n.id) ?? 0;
|
|
|
|
//ID更新集合
|
|
var updateIds = DataConvert.ConvertToInt32Set(updateKeyIds);
|
|
|
|
if (maxId < minId)
|
|
{
|
|
minId = -1;
|
|
}
|
|
|
|
if (maxId == minId && !updateIds.Any(n => n > 0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_lastUptime = DateTime.Now;
|
|
|
|
//数据查询
|
|
var query = table.Where(n => (n.id > minId && n.id <= maxId) || updateIds.Contains(n.id));
|
|
if (Filter != null)
|
|
{
|
|
query = query.Where(Filter);
|
|
}
|
|
var datas = query.OrderBy(n => n.id).ToArray();
|
|
|
|
datas = PreProcessDatas(datas);
|
|
|
|
lock (this)
|
|
{
|
|
//更新字典数据
|
|
foreach (var data in datas)
|
|
{
|
|
updateIds.Remove(data.id);
|
|
_dic[data.id] = data;
|
|
AfterUpdate?.Invoke(data);
|
|
}
|
|
|
|
//取不到数据的直接从本地字典中删除
|
|
updateIds.Remove(0);
|
|
foreach (var id in updateIds)
|
|
{
|
|
if (AfterRemove != null && _dic.TryGetValue(id, out var data))
|
|
{
|
|
AfterRemove(data);
|
|
}
|
|
_dic.Remove(id);
|
|
}
|
|
}
|
|
|
|
_maxId = maxId;
|
|
|
|
DataSourceUpdated?.Invoke(this, EventArgs.Empty);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据KeyID获取数据
|
|
/// </summary>
|
|
public virtual TData GetData(int keyId)
|
|
{
|
|
if (keyId < 1)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
lock (this)
|
|
{
|
|
if (_dic.TryGetValue(keyId, out TData data))
|
|
{
|
|
return _clonable ? ((IClonable<TData>)data).Clone() : data;
|
|
}
|
|
|
|
using (var db = CreateDbContext())
|
|
{
|
|
var dbModel = db.Set<TData>().AsNoTracking().FirstOrDefault(n => n.id == keyId);
|
|
if (dbModel != null)
|
|
{
|
|
_dic[dbModel.id] = dbModel;
|
|
AfterUpdate?.Invoke(dbModel);
|
|
return _clonable ? ((IClonable<TData>)dbModel).Clone() : dbModel;
|
|
}
|
|
return dbModel;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 重置数据源
|
|
/// </summary>
|
|
public virtual void ResetDataSource()
|
|
{
|
|
_maxId = -1;
|
|
_dic.Clear();
|
|
}
|
|
|
|
//--------用于扩展配置------------------
|
|
|
|
/// <summary>
|
|
/// 数据加载后预处理
|
|
/// </summary>
|
|
protected virtual TData[] PreProcessDatas(TData[] datas)
|
|
{
|
|
return datas;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 查询过滤条件
|
|
/// </summary>
|
|
public Expression<Func<TData, bool>> Filter { get; set; }
|
|
|
|
/// <summary>
|
|
/// 更新以后事件处理
|
|
/// </summary>
|
|
public Action<TData> AfterUpdate { get; set; }
|
|
|
|
/// <summary>
|
|
/// 删除以后事件处理
|
|
/// </summary>
|
|
public Action<TData> AfterRemove { get; set; }
|
|
|
|
/// <summary>
|
|
/// 创建数据库上下文(默认使用YLContext)
|
|
/// </summary>
|
|
protected virtual DbContext CreateDbContext()
|
|
{
|
|
return DbContextFactory.GetYLDbContext();
|
|
}
|
|
|
|
public string ToJson()
|
|
{
|
|
return new { _maxId, _lastUptime, _dic }.ToJson();
|
|
}
|
|
}
|
|
}
|