添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

先说一下打算怎么实现这个功能。

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混合项目。