技术 思绪 摘录 旅行
需求来源:一条数据被编辑之后,日志要记录下改动了什么项,从什么改成什么了,还得可以指定某些字段,比如用户表,只要改了用户名,就记录一下日志,业务可以根据是否有修改来发送通知啊或者启用禁用啊这些操作。

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

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 就是变动的描述,多个字段变动,则多条描述。


CarsonIT 微信扫码关注公众号 策略、创意、技术

留下您的脚步

 

最近评论

查看更多>>

友情打赏

请打开您的微信,扫一扫