278 lines
8.7 KiB
C#
278 lines
8.7 KiB
C#
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
|
using YLErp;
|
|
|
|
namespace BaseOUDAL
|
|
{
|
|
/// <summary>
|
|
/// 数据变化追踪
|
|
/// </summary>
|
|
public class DataChangeTracer
|
|
{
|
|
List<DataTrace> _list;
|
|
List<(DataTrace, EntityEntry)> _listAdded;
|
|
|
|
readonly DBContextBase _dbcontext;
|
|
readonly Dictionary<string, string> _dicNew;
|
|
//readonly Dictionary<string, string> _dicOld;
|
|
|
|
public DataChangeTracer(DBContextBase dbcontext)
|
|
{
|
|
_dbcontext = dbcontext ?? throw new ArgumentNullException(nameof(dbcontext));
|
|
|
|
_dicNew = new Dictionary<string, string>();
|
|
//_dicOld = new Dictionary<string, string>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 添加数据跟踪
|
|
/// </summary>
|
|
public DataChangeTracer AddTraces(OptUserInfo optUserInfo)
|
|
{
|
|
var entityList = _dbcontext.ChangeTracker.Entries()
|
|
.Where(p => p.State > EntityState.Unchanged && p.Entity is IDataTrace).ToArray();
|
|
|
|
if (entityList.Length < 1)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
if (_list == null)
|
|
{
|
|
_list = new List<DataTrace>(entityList.Length);
|
|
}
|
|
|
|
foreach (var entityEntry in entityList)
|
|
{
|
|
var dataTrace = GetDataTrace(entityEntry, optUserInfo);
|
|
|
|
if (dataTrace == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
_list.Add(dataTrace);
|
|
|
|
if (dataTrace.TraceFlag == 1 && entityEntry.State == EntityState.Added)
|
|
{
|
|
if (_listAdded == null)
|
|
{
|
|
_listAdded = new List<(DataTrace, EntityEntry)>();
|
|
}
|
|
|
|
_listAdded.Add((dataTrace, entityEntry));
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存数据跟踪
|
|
/// </summary>
|
|
public async void SaveTracesAsync()
|
|
{
|
|
if (_list == null || _list.Count < 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DataTraceDbContext db = null;
|
|
|
|
try
|
|
{
|
|
if (_listAdded != null)
|
|
{
|
|
foreach (var (trace, entry) in _listAdded)
|
|
{
|
|
trace.DataKeyId = GetKeyValue(entry);
|
|
}
|
|
}
|
|
|
|
db = _dbcontext.GetDataTraceDbContext();
|
|
db.DataTrace.AddRange(_list);
|
|
await db.SaveChangesAsync().ContinueWith(t =>
|
|
{
|
|
if (t.Exception != null)
|
|
{
|
|
LogFactory.GetLogger<DataChangeTracer>().Error(t.Exception);
|
|
}
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger<DataChangeTracer>().Error(ex);
|
|
}
|
|
finally
|
|
{
|
|
db?.Dispose();
|
|
}
|
|
}
|
|
|
|
private DataTrace GetDataTrace(EntityEntry entityEntry, OptUserInfo optUserInfo)
|
|
{
|
|
if (entityEntry.Entity is IDataTraceIgnore traceIgnore && traceIgnore.IgnoreDataTrace())
|
|
{
|
|
return null;
|
|
}
|
|
|
|
string dataChanges = GetDataChanges(entityEntry);
|
|
|
|
var traceFlag = 0;
|
|
var keyInfo = string.Empty;
|
|
|
|
switch (entityEntry.State)
|
|
{
|
|
case EntityState.Added:
|
|
traceFlag = 1;
|
|
keyInfo = "新增";
|
|
break;
|
|
case EntityState.Modified:
|
|
traceFlag = 2;
|
|
keyInfo = "修改";
|
|
if (string.IsNullOrEmpty(dataChanges))
|
|
{
|
|
return null;
|
|
}
|
|
break;
|
|
case EntityState.Deleted:
|
|
traceFlag = 3;
|
|
keyInfo = "删除";
|
|
break;
|
|
}
|
|
|
|
keyInfo += ((IDataTrace)entityEntry.Entity).GetDataTraceKeyInfo();
|
|
|
|
var keyId = string.Empty;
|
|
|
|
if (entityEntry.Entity is IDataTraceV2 dataTraceV2)
|
|
{
|
|
keyId = dataTraceV2.GetDataTraceKeyId() ?? string.Empty;
|
|
traceFlag = string.IsNullOrEmpty(keyId) || keyId == "0" ? 1 : traceFlag + 100;
|
|
}
|
|
else if (entityEntry.State != EntityState.Added)
|
|
{
|
|
keyId = GetKeyValue(entityEntry);
|
|
}
|
|
|
|
var user = optUserInfo ?? OptUserInfo.SystemUser;
|
|
|
|
var entityType = entityEntry.Entity.GetType();
|
|
var tableName = entityType.Name;
|
|
|
|
if (entityEntry.Entity is IDataTraceV3 traceV3)
|
|
{
|
|
var tableName2 = traceV3.GetDataTraceTableName();
|
|
if (!string.IsNullOrEmpty(tableName2))
|
|
{
|
|
tableName = tableName2;
|
|
}
|
|
}
|
|
|
|
return new DataTrace
|
|
{
|
|
TableName = tableName,
|
|
DataState = entityEntry.State.ToString(),
|
|
CreateTime = DateTime.Now,
|
|
DataKeyId = keyId,
|
|
DataKeyInfo = keyInfo,
|
|
OptId = user.UserId,
|
|
OptName = user.UserName,
|
|
IpAddress = user.IpAddress,
|
|
DataChanges = dataChanges,
|
|
//OldValues = oldValues,
|
|
TraceFlag = traceFlag
|
|
};
|
|
}
|
|
|
|
private static string GetKeyValue(EntityEntry entry)
|
|
{
|
|
var keyProps = entry.Metadata.FindPrimaryKey().Properties;
|
|
|
|
if (keyProps == null || keyProps.Count < 1)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
if (keyProps.Count > 0 && "id".Equals(keyProps[0].Name, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return entry.Property(keyProps[0].Name).CurrentValue?.ToString();
|
|
}
|
|
|
|
return keyProps.ToDictionary(n => n.Name, m => entry.Property(m.Name).CurrentValue?.ToString()).ToJson();
|
|
}
|
|
|
|
private string GetDataChanges(EntityEntry entry)
|
|
{
|
|
PropertyValues dbValues = null;
|
|
|
|
if (entry.State != EntityState.Added)
|
|
{
|
|
dbValues = entry.GetDatabaseValues();
|
|
|
|
//等于null说明这个实体对象在数据库中无值但在实体上下文中做了变更(比如事务或附加)
|
|
|
|
if (dbValues?.Properties == null || !dbValues.Properties.Any())
|
|
{
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
var dic = new Dictionary<string, string>();
|
|
|
|
var properties = dbValues?.Properties ?? entry.CurrentValues.Properties;
|
|
|
|
foreach (var prop in properties)
|
|
{
|
|
if (ExclueNames.Contains(prop.Name))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
switch (entry.State)
|
|
{
|
|
case EntityState.Added:
|
|
{
|
|
var newVal = entry.CurrentValues[prop];
|
|
if (newVal != null)
|
|
{
|
|
dic[prop.Name] = Convert.ToString(newVal);
|
|
}
|
|
}
|
|
break;
|
|
case EntityState.Deleted:
|
|
{
|
|
var oldVal = dbValues[prop];
|
|
if (oldVal != null)
|
|
{
|
|
dic[prop.Name] = Convert.ToString(oldVal);
|
|
}
|
|
}
|
|
break;
|
|
case EntityState.Modified:
|
|
{
|
|
var oldVal = dbValues[prop];
|
|
var newVal = entry.CurrentValues[prop];
|
|
var newValStr = Convert.ToString(newVal);
|
|
var oldValStr = Convert.ToString(oldVal);
|
|
if (!Equals(newValStr, oldValStr))
|
|
{
|
|
dic[prop.Name] = newValStr;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return dic.Count > 0 ? dic.ToJson() : string.Empty;
|
|
}
|
|
|
|
readonly static IEnumerable<string> ExclueNames = new string[]
|
|
{
|
|
nameof(DBModelWithOperator.id),
|
|
nameof(DBModelWithOperator.OptId),
|
|
nameof(DBModelWithOperator.OptName),
|
|
nameof(DBModelWithOperator.OptDate),
|
|
nameof(SystemUser.UserToken),
|
|
};
|
|
}
|
|
} |