• 利用反射来做‘历史变更’记录


    十年河东,十年河西,莫欺少年穷!

    学无止境,精益求精!

    有这样一个需求,要求操作数据库时‘留痕’,具体需求如下:

    假设操作如下一张表:

    create table Student
    (
    StudentId varchar(100) primary key not null,
    StudentName nvarchar(20),--姓名
    StudentNo varchar(10),--学号
    SutdentSex varchar(1),--性别
    ProvinceFrom nvarchar(50),--省份
    CityFrom nvarchar(50),--城市
    CreateDate datetime default(getdate()),
    )

    需求如下:当更新学生表时,要求记录如下信息:

    create table ChangeHistory
    (
    HistoryId varchar(100) primary key not null,
    ChangeField  nvarchar(50),--所修改字段的中文含义
    BeforeChangeValue nvarchar(100),--修改前的值
    AfterChangeValue nvarchar(100),--修改后的值
    ChangeBy nvarchar(20),--修改人
    ChangeTime datetime,--修改时间
    )

    看到上述两张表,你会不会感觉很简单呢?

    可能会有人立马想到一个笨方法,如下:

    List<StudentModel> DataBaseStudentList = new List<StudentModel>();//用于模拟数据库学生表中的4条记录
            protected void Page_Load(object sender, EventArgs e)
            {
                //学生一
                StudentModel M1 = new StudentModel()
                {
                    StudentId = "01",
                    CityFrom = "苏州",
                    ProvinceFrom = "江苏",
                    StudentName = "啊龙",
                    StudentNo = "081309201",
                    SutdentSex = ""
                };
                //学生二
                StudentModel M2 = new StudentModel()
                {
                    StudentId = "02",
                    CityFrom = "苏州",
                    ProvinceFrom = "江苏",
                    StudentName = "阿狗",
                    StudentNo = "081309202",
                    SutdentSex = ""
                };
                //学生三
                StudentModel M3 = new StudentModel()
                {
                    StudentId = "03",
                    CityFrom = "苏州",
                    ProvinceFrom = "江苏",
                    StudentName = "阿猫",
                    StudentNo = "081309203",
                    SutdentSex = ""
                };
                //学生四
                StudentModel M4 = new StudentModel()
                {
                    StudentId = "04",
                    CityFrom = "苏州",
                    ProvinceFrom = "江苏",
                    StudentName = "阿猪",
                    StudentNo = "081309204",
                    SutdentSex = ""
                };
                DataBaseStudentList.Add(M1);
                DataBaseStudentList.Add(M2);
                DataBaseStudentList.Add(M3);
                DataBaseStudentList.Add(M4);
                //数据库填充完后,我们修改学生表
                string StudentId = "03";
                StudentModel ef = DataBaseStudentList.Where(A => A.StudentId == StudentId).FirstOrDefault();
                if (ef != null)
                {
                    ef.StudentName = "阿狸猫";//修改了姓名
                }
                //调用历史变更的方法。
                UpdateStudent(ef, StudentId);
            }
    
            public void UpdateStudent(StudentModel newModel, string StudentId)
            {
                List<ChangeHistoryModel> ChangeHistoryList = new List<ChangeHistoryModel>();
                var oldef = DataBaseStudentList.Where(A => A.StudentId == StudentId).FirstOrDefault();
                if(oldef.CityFrom!= newModel.CityFrom)
                {
                    ChangeHistoryModel M = new ChangeHistoryModel()
                    {
                        HistoryId = Guid.NewGuid().ToString(),
                        ChangeField = "学生所属城市",
                        BeforeChangeValue = oldef.CityFrom,
                        AfterChangeValue = newModel.CityFrom,
                        ChangeBy = "修改人姓名",
                        ChangeTime = DateTime.Now
                    };
                }
    
                if (oldef.ProvinceFrom != newModel.ProvinceFrom)
                {
                    ChangeHistoryModel M = new ChangeHistoryModel()
                    {
                        HistoryId = Guid.NewGuid().ToString(),
                        ChangeField = "学生所属省份",
                        BeforeChangeValue = oldef.ProvinceFrom,
                        AfterChangeValue = newModel.ProvinceFrom,
                        ChangeBy = "修改人姓名",
                        ChangeTime = DateTime.Now
                    };
                }
    
                if (oldef.StudentName != newModel.StudentName)
                {
                    ChangeHistoryModel M = new ChangeHistoryModel()
                    {
                        HistoryId = Guid.NewGuid().ToString(),
                        ChangeField = "学生姓名",
                        BeforeChangeValue = oldef.StudentName,
                        AfterChangeValue = newModel.StudentName,
                        ChangeBy = "修改人姓名",
                        ChangeTime = DateTime.Now
                    };
                }
                /*
                ...
                ... 等等其他字段的修改
                ...
                */
    
                //最后将历史变更插入数据库
            }
    View Code

    上述的方法是通过每个字段作比对,如果不一致,则生成变更记录,这种方法实现了上述要求,但如果有上百个字段,那么...

    OK,下面我们用反射结合.config文件来实现!

     1、新建SelectItem.config文件,用来将数据表字段对应中文含义,如下:

    <?xml version="1.0" encoding="utf-8"?>
    <config>
      <!--学生信息解读 反射案例 历史变更记录-->
      <StudentInfo value="StudentName">学生姓名</StudentInfo>
      <StudentInfo value="StudentNo">学号</StudentInfo>
      <StudentInfo value="SutdentSex">性别</StudentInfo>
      <StudentInfo value="ProvinceFrom">省份</StudentInfo>
      <StudentInfo value="CityFrom">城市</StudentInfo>
    </config>

    2、创建两个Model,一个OldModel,代表没修改之前的Model,一个NewModel,代表修改后的Model,如下:

        public class StudentOldModel
        {
            public string StudentId { get; set; }
            public string StudentName { get; set; }
            public string StudentNo { get; set; }
            public string SutdentSex { get; set; }
            public string ProvinceFrom { get; set; }
            public string CityFrom { get; set; }
            public string CreateDate { get; set; }
        }
    
        public class StudentNewModel
        {
            public string StudentId { get; set; }
            public string StudentName { get; set; }
            public string StudentNo { get; set; }
            public string SutdentSex { get; set; }
            public string ProvinceFrom { get; set; }
            public string CityFrom { get; set; }
            public string CreateDate { get; set; }
        }
    View Code

    3、构造老的OldModel,和新的NewModel,如下:

    //来自数据库
                StudentOldModel M1 = new StudentOldModel()
                {
                    StudentId = "01",
                    CityFrom = "苏州",
                    ProvinceFrom = "江苏",
                    StudentName = "啊龙",
                    StudentNo = "081309201",
                    SutdentSex = ""
                };
    
                //用户修改后
                StudentNewModel M2 = new StudentNewModel()
                {
                    StudentId = "01",
                    CityFrom = "郑州",
                    ProvinceFrom = "河南",
                    StudentName = "啊龙",
                    StudentNo = "081309201",
                    SutdentSex = ""
                };
    View Code

    4、利用反射结合.config文件记录变更如下:

           public static void UpdateHistory(StudentNewModel newModel, StudentOldModel oldModel, string modifyUserName, string modifyWeb)
            {
                List<ChangeHistoryModel> ChangeHistoryModelList = new List<ChangeHistoryModel>();
                Type t = newModel.GetType();
                PropertyInfo[] PropertyList = t.GetProperties();
                //
                Type tSource = oldModel.GetType();
                PropertyInfo[] SourcePropertyList = tSource.GetProperties();
                var ls = PropertyList.GroupBy(a => a.PropertyType.Name).Select(g => (new { a = g.Key, count = g.Count() })).ToList();
                foreach (PropertyInfo item in PropertyList)
                {
                    string name = item.Name;
                    string Filed =SelectHelper. GetFiled(name);
                    object value = item.GetValue(newModel, null);
                    PropertyInfo ef = SourcePropertyList.Where(A => A.Name.ToLower() == name.ToLower()).FirstOrDefault();
                    string PropertyType = item.PropertyType.Name;
                    if (PropertyType == "String")
                    {
                        string ToValue = value == null ? "" : value.ToString();
                        if (ef != null)
                        {
                            object Value2 = ef.GetValue(oldModel, null);
                            string ScoureValue = Value2 == null ? "" : Value2.ToString();
                            if ((ToValue != ScoureValue))
                            {
                                if (!string.IsNullOrEmpty(Filed))
                                {
                                    ChangeHistoryModel CM = new ChangeHistoryModel()
                                    {
                                        ChangeField = Filed,
                                        BeforeChangeValue = ScoureValue,
                                        AfterChangeValue = ToValue,
                                        HistoryId = Guid.NewGuid().ToString(),
                                        ChangeBy = "修改人姓名",
                                        ChangeTime = DateTime.Now
                                    };
                                    ChangeHistoryModelList.Add(CM);
                                }
                            }
                        }
                    }
                }
            }
    View Code

    上述就可以动态完成变更记录的生成了!需要说明的是:不管数据库字段是什么数据类型,我们要把所有字段转化为Model中的字符串类型String,

    需要辅助类如下:

        public class SelectHelper
        {
            private static SelectItemConfig configManager;
            public static Dictionary<string, string> GetConfigByKey(string key, string name = "SelectItem.config")
            {
                string mapPath = HttpContext.Current.Server.MapPath("~/");
                configManager = new SelectItemConfig(mapPath, name);
                Dictionary<string, string> dic = configManager.getItemListByKey(key);
                return dic.OrderBy(p => p.Value).ToDictionary(o => o.Key, p => p.Value); ;
            }
    
            public static Dictionary<string, string> GetConfigByKeyForFields(string key, string name = "SelectItem.config")
            {
                string mapPath = HttpContext.Current.Server.MapPath("~/");
                configManager = new SelectItemConfig(mapPath, name);
                Dictionary<string, string> dic = configManager.getItemListByKey(key);
                return dic;
            }
    
            /// <summary>
            /// 获取XML文件中某一节点的值
            /// </summary>
            /// <param name="name"></param>
            /// <returns></returns>
            public static string GetFiled(string name)
            {
                Dictionary<string, string> dic = SelectHelper.GetConfigByKey("StudentInfo");
                string Filed = string.Empty;
                foreach (var item in dic)
                {
                    if (item.Key.ToLower() == name.ToLower())
                    {
                        Filed = item.Value;
                        break;
                    }
                }
                return Filed;
            }
        }
    
        public class SelectItemConfig
        {
            private XmlDocument _doc;
            private XmlNode _rootNode;
    
            public SelectItemConfig(String mapPath, string name)
            {
                _doc = new XmlDocument();
                _doc.Load(mapPath + name);
                _rootNode = _doc.DocumentElement;
            }
    
            public void setConfig(String key, String value)
            {
                if (value == null || (value != null && value.Length == 0)) { return; }
    
                if (_rootNode.SelectSingleNode(key) == null || (_rootNode.SelectSingleNode(key) != null && _rootNode.SelectSingleNode(key).ChildNodes.Count == 0))
                {
                    XmlElement newNode = _doc.CreateElement(key);
                    newNode.InnerText = value;
                    _rootNode.AppendChild(newNode);
                }
                else
                {
                    _rootNode.SelectSingleNode(key).ChildNodes[0].InnerText = value;
                }
            }
    
            /// <summary>
            /// 获取单个节点的值
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public String getConfig(string key)
            {
                if (_rootNode.SelectSingleNode(key) != null)
                    if (_rootNode.SelectSingleNode(key).ChildNodes.Count > 0)
                        return _rootNode.SelectSingleNode(key).ChildNodes[0].Value;
                    else
                        return "";
                else
                    return null;
            }
    
            /// <summary>
            /// 获取key值对应的多个节点的值的集合
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public Dictionary<string, string> getItemListByKey(string key)
            {
                Dictionary<string, string> dic = new Dictionary<string, string>() { };
                if (_rootNode.SelectSingleNode(key) != null)
                {
                    XmlNodeList xmlNode = _rootNode.SelectNodes(key);
                    int nodeCount = _rootNode.SelectNodes(key).Count;
                    if (nodeCount > 0)
                    {
                        for (int i = 0; i < nodeCount; i++)
                        {
                            var item = _rootNode.SelectNodes(key).Item(i);
                            dic.Add(item.Attributes["value"].Value, item.InnerText);//Select 下拉框 Value属性
                        }
                    }
                }
                return dic;
            }
    
            public Boolean SaveConfig(String mapPath)
            {
                try
                {
                    _doc.Save(mapPath + @"FlexPaper.config");
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }
    View Code

    @陈卧龙的博客

  • 相关阅读:
    新来一个技术总监:禁止戴耳机写代码,发现就扣绩效。。
    面试官:为什么数据库连接池不采用 IO 多路复用?我懵逼了。。
    重磅!Spring Boot 2.7 正式发布,一大波新特性,看完我彻底躺平了。。
    Spring Boot + Mybatis Plus + ClickHouse 轻松实现增删改查,看了必懂。。
    证书服务(一)非对称加密RSA,ssh使用密钥登录
    大叔问题定位分享(45)hive任务udf函数偶尔报错
    大叔经验分享(133)hive元数据中location修复
    大叔问题定位分享(44)kafka服务重启
    蒙东出图总结
    arcgis 栅格拼接
  • 原文地址:https://www.cnblogs.com/chenwolong/p/changeHistory.html
Copyright © 2020-2023  润新知