Files
zszq-trs/YLErpDAL/Modules/DataCacheModule/DataSource/GenericeCachedDataSource.cs
T
2024-05-09 14:06:26 +08:00

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();
}
}
}