先说一下打算怎么实现这个功能。
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}]");
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 就是变动的描述,多个字段变动,则多条描述。
Resharper 2021.3.2-VS2022可用的扩展插件
ReSharper是一个JetBrains公司出品的著名的代码生成工具。其能帮助Microsoft Visual Studio成为一个更佳的IDE,它包括一系列丰富的能大大增加C#和Visual Basic .net开发者生产力的特征。使用ReSharper,你可以进行深度代码分析,智能代码协助,实时错误代码高亮显示,解决方案范围内代码分析,快速代码更正,一步完成代码格式化和清理,业界领先的自动代码重构,高级的集成单元测试方案,和强大的解决方案内导航和搜索。实质上,ReSharper特征可用于C#,VB.NET,XML,ASP.NET,XAML,和构建脚本。ReSharper还为C#和VB.NET提供了增强的交叉语言功能,它使开发者可以有效的控制.net混合项目。