先说一下打算怎么实现这个功能。
1、数据表一般映射实体类,所以我们从实体类入手。
2、实体类属性太多,所以达到对比效果需要用反射,肯定不能用if来单个对比。
3、还得能定制,只对比指定的一些字段,所以考虑把属性的特性融入进去。
基于这三点要求,先申明一个特性:FieldNameAttribute.cs
/// <summary>
/// 字段名标注
/// </summary>
/// <seealso cref="System.Attribute" />
public class FieldNameAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="FieldNameAttribute"/> class.
/// </summary>
/// <param name="name">The name.</param>
public FieldNameAttribute(string name)
{
}
}再写操作方法辅助类:CompareDataHelper.cs
/// <summary>
/// 比较实体类
/// </summary>
public class CompareDataHelper
{
/// <summary>
/// 比较两个实体类差异
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="newModel">新的model</param>
/// <param name="oldModel">原来的model</param>
/// <param name="isAttr">是否有FieldNameAttribute特性</param>
/// <returns></returns>
public static List<string> CompareToString<T>(T newModel, T oldModel, bool isAttr = false)
{
List<string> data = new List<string>();
if (newModel == null || oldModel == null)
{
return null;
}
PropertyInfo[] newProperties = newModel.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
PropertyInfo[] oldProperties = oldModel.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
if (newProperties.Length <= 0 || oldProperties.Length <= 0)
{
return null;
}
var oldFieldLst = new Dictionary<string, string>();
foreach (PropertyInfo item in oldProperties)
{
string filedName = string.Empty;
if (isAttr)
{
var fieldAttribute = item.CustomAttributes.FirstOrDefault(t => t.AttributeType == typeof(FieldNameAttribute));
filedName = fieldAttribute?.ConstructorArguments[0].Value?.ToString() ?? "";
if (string.IsNullOrWhiteSpace(filedName))
{
continue;
}
}
string name = item.Name;//实体类字段名称
string value = item.GetValue(oldModel, null)?.ToString() ?? "";//该字段的值
if (item.PropertyType.IsValueType || item.PropertyType.Name.StartsWith("String"))
{
oldFieldLst.Add(isAttr ? filedName : name, value);//在此可转换value的类型
}
}
foreach (PropertyInfo item in newProperties)
{
string filedName = string.Empty;
if (isAttr)
{
var fieldAttribute = item.CustomAttributes.FirstOrDefault(t => t.AttributeType == typeof(FieldNameAttribute));
filedName = fieldAttribute?.ConstructorArguments[0].Value?.ToString() ?? "";
if (string.IsNullOrWhiteSpace(filedName))
{
continue;
}
}
string name = item.Name;//实体类字段名称
string value = item.GetValue(newModel, null)?.ToString() ?? "";//该字段的值
filedName = isAttr ? filedName : name;
if (oldFieldLst.ContainsKey(filedName))
{
string olddata = oldFieldLst[filedName];
if (olddata != value)
{
data.Add($"修改[{filedName}],从[{olddata}]到[{value}]");
}
}
else
{
data.Add($"新增[{filedName}]");
}
}
return data;
}
}再看需要对比的实体类:
/// <summary>
/// 测试用户表
/// </summary>
public class Users
{
/// <summary>
/// Gets or sets the user identifier.
/// </summary>
/// <value>
/// The user identifier.
/// </value>
public int UserID { get; set; }
/// <summary>
/// Gets or sets the name of the user.
/// </summary>
/// <value>
/// The name of the user.
/// </value>
public string UserName { get; set; }
/// <summary>
/// Gets or sets the email.
/// </summary>
/// <value>
/// The email.
/// </value>
[FieldName("邮箱地址")]
public string Email { get; set; }
/// <summary>
/// Gets or sets the address.
/// </summary>
/// <value>
/// The address.
/// </value>
[FieldName("家庭住址")]
public string Address { get; set; }
}注意看,这个users实体类,其中只有两个属性有FieldName特性,也就是说,如果对比,可以只对比这两个属性。
看调用方式:
Users olddata=DbHeler.Select("查询条件");//老数据
Users newdata=new Users();//新数据
List<string> compstrlst = CompareDataHelper.CompareToString<Users>(newdata, olddata);//执行对比方法List<string> compstrlst 就是变动的描述,多个字段变动,则多条描述。
川公网安备 51010702003150号
留下您的脚步
最近评论