using System.Linq.Expressions;
using YLErp.Abstract;
namespace YLErp.Modules.DataCacheModule
{
///
/// 通用数据源抽象类
///
abstract class GenericeCachedDataSource : IDataUpdater, IDataSource, IDataSource, IDataSourceEvent, IJsonSerializable
where TData : class, IDataTraceV2, IDataEntity
{
protected int _maxId = -1;
protected bool _clonable;
protected readonly Dictionary _dic;
protected DateTime _lastUptime;
public event EventHandler DataSourceUpdated;
protected GenericeCachedDataSource()
{
_dic = new Dictionary();
_clonable = typeof(TData).GetInterface(typeof(IClonable).Name) != null;
}
///
/// 数据条数
///
public int Count => _dic.Count;
public abstract string TableName { get; }
///
/// 获取数据
///
public IQueryable AsQueryable(Expression> predicate = null)
{
lock (this)
{
if (_dic.Count < 1)
{
return Enumerable.Empty().AsQueryable();
}
var query = _dic.Values.AsQueryable();
if (predicate != null)
{
query = query.Where(predicate);
}
if (_clonable)
{
return new DataCacheQueryable(query);
}
return query;
}
}
///
/// 更新数据源
///
public virtual void UpdateData(IEnumerable updateKeyIds)
{
lock (_dic)
{
InnerUpdateData(updateKeyIds);
}
}
private void InnerUpdateData(IEnumerable updateKeyIds)
{
using (var db = CreateDbContext())
{
var table = db.Set().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);
}
}
///
/// 根据KeyID获取数据
///
public virtual TData GetData(int keyId)
{
if (keyId < 1)
{
return null;
}
lock (this)
{
if (_dic.TryGetValue(keyId, out TData data))
{
return _clonable ? ((IClonable)data).Clone() : data;
}
using (var db = CreateDbContext())
{
var dbModel = db.Set().AsNoTracking().FirstOrDefault(n => n.id == keyId);
if (dbModel != null)
{
_dic[dbModel.id] = dbModel;
AfterUpdate?.Invoke(dbModel);
return _clonable ? ((IClonable)dbModel).Clone() : dbModel;
}
return dbModel;
}
}
}
///
/// 重置数据源
///
public virtual void ResetDataSource()
{
_maxId = -1;
_dic.Clear();
}
//--------用于扩展配置------------------
///
/// 数据加载后预处理
///
protected virtual TData[] PreProcessDatas(TData[] datas)
{
return datas;
}
///
/// 查询过滤条件
///
public Expression> Filter { get; set; }
///
/// 更新以后事件处理
///
public Action AfterUpdate { get; set; }
///
/// 删除以后事件处理
///
public Action AfterRemove { get; set; }
///
/// 创建数据库上下文(默认使用YLContext)
///
protected virtual DbContext CreateDbContext()
{
return DbContextFactory.GetYLDbContext();
}
public string ToJson()
{
return new { _maxId, _lastUptime, _dic }.ToJson();
}
}
}