先说一下打算怎么实现这个功能。
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 就是变动的描述,多个字段变动,则多条描述。
留下您的脚步
最近评论