C# 实体更新记录:如何捕获和记录字段变化到日志

方案一:粗糙但可用
 

var changes = new List<string>();void CompareAndAddChange<T>(string propertyName, T oldValue, T newValue, Func<T, string> descriptionFunc = null)
{if (!EqualityComparer<T>.Default.Equals(oldValue, newValue)){var oldValueStr = descriptionFunc != null ? descriptionFunc(oldValue) : oldValue.ToString();var newValueStr = descriptionFunc != null ? descriptionFunc(newValue) : newValue.ToString();changes.Add($"{propertyName}: [{oldValueStr}] => [{newValueStr}]");}
}CompareAndAddChange("公司名称", cusOld.CompanyName, modelDto.CompanyName);
CompareAndAddChange("公司类型", cusOld.CompanyType, modelDto.CompanyType, x => x.GetDescription());
CompareAndAddChange("公司代码", cusOld.CompanyCode, modelDto.CompanyCode);
CompareAndAddChange("公司介绍", cusOld.Contents, modelDto.Contents);
CompareAndAddChange("会员等级", cusOld.MemberLevel, modelDto.MemberLevel, x => x.GetDescription());
CompareAndAddChange("会员类型", cusOld.MemberType, modelDto.MemberType, x => x.GetDescription());
CompareAndAddChange("业务员", cusOld.SaleId, modelDto.SaleId, async id =>
{var user = await _userRepository.GetWhereAsync(x => x.Id == id);return user?.NickName ?? id.ToString();
});
CompareAndAddChange("点数", cusOld.Ratio, modelDto.Ratio);
CompareAndAddChange("联系方式", cusOld.Phone, modelDto.Phone);
CompareAndAddChange("会员有效期", cusOld.MemberValidityPeriod, modelDto.MemberValidityPeriod);
CompareAndAddChange("最大API客户数", cusOld.MaxApiCusCount, modelDto.MaxApiCusCount);
CompareAndAddChange("最大渠道数", cusOld.MaxChannelCount, modelDto.MaxChannelCount);
CompareAndAddChange("最大供应商数", cusOld.MaxSupplierCount, modelDto.MaxSupplierCount);
CompareAndAddChange("备注", cusOld.Remark, modelDto.Remark);var content = string.Join(",", changes);

这种优化方式做了以下改进:

  1. 单一函数处理比较和改变的添加:使用泛型方法 CompareAndAddChange 来处理每个属性的比较和变更添加,避免了重复的逻辑。

  2. 异步处理:在需要获取业务员信息时,通过异步方法从 _userRepository 中获取用户信息。

  3. 描述函数:对于特定属性(如枚举类型),提供了描述函数,用于获取更具描述性的字符串,提高了可读性。

这种方法不仅减少了代码量,还提高了可维护性和可扩展性,使得未来对属性的改动更易于处理和扩展。


方案二:优化更舒服、反射

var changes = new List<string>();// 获取所有属性
var properties = typeof(ModelDto).GetProperties();foreach (var property in properties)
{// 获取属性值var oldValue = property.GetValue(cusOld);var newValue = property.GetValue(modelDto);// 如果新旧值不相等if (!Equals(oldValue, newValue)){// 特殊处理 SaleId 属性if (property.Name == "SaleId"){var userNew = await _userRepository.GetWhereAsync(x => x.Id == (int)newValue);var userOld = await _userRepository.GetWhereAsync(x => x.Id == (int)oldValue);changes.Add($"业务员: [{userOld?.NickName}] => [{userNew?.NickName}]");}else{changes.Add($"{property.Name}: [{oldValue}] => [{newValue}]");}}
}var content = string.Join(",", changes);

这种方法的优点包括:

  1. 自动化属性比较:利用反射获取 ModelDto 的所有属性,并比较旧值和新值。

  2. 特殊处理:对于特定属性(如 SaleId),可以根据需要进行特殊处理,例如异步获取用户信息。

  3. 简化代码:避免了手动编写每个属性的比较逻辑,使代码更加简洁和易于维护。

  4. 可扩展性:如果需要比较的属性增加或者需要额外的特殊处理,只需在相应的位置添加逻辑即可。

这种方法适合于需要自动化处理属性比较和生成变更日志的场景,能够有效地提高代码的复用性和可维护性。

方案三:进阶加描述

如果你想要在使用反射时获取属性的自定义备注或描述,你可以借助 C# 中的自定义属性来实现。以下是一个简单的示例,展示如何定义一个自定义属性,并在反射时使用它获取字段的备注:

首先,定义一个自定义属性类 FieldDescriptionAttribute

[AttributeUsage(AttributeTargets.Property)]
public class FieldDescriptionAttribute : Attribute
{public string Description { get; }public FieldDescriptionAttribute(string description){Description = description;}
}

然后,在你的 ModelDto 类中使用这个自定义属性:

public class ModelDto
{[FieldDescription("公司名称")]public string CompanyName { get; set; }[FieldDescription("公司类型")]public CompanyType CompanyType { get; set; }[FieldDescription("公司代码")]public string CompanyCode { get; set; }// 其他属性省略
}

接下来,在生成变更内容时,使用这些自定义属性来获取字段的备注:

var changes = new List<string>();var properties = typeof(ModelDto).GetProperties();foreach (var property in properties)
{var oldValue = property.GetValue(cusOld);var newValue = property.GetValue(modelDto);if (!Equals(oldValue, newValue)){// 获取属性上的 FieldDescriptionAttributevar descriptionAttribute = (FieldDescriptionAttribute)property.GetCustomAttributes(typeof(FieldDescriptionAttribute), false).FirstOrDefault();// 如果找到了 FieldDescriptionAttribute,则使用其描述,否则使用属性名var propertyName = descriptionAttribute != null ? descriptionAttribute.Description : property.Name;// 特殊处理 SaleId 属性if (property.Name == "SaleId"){var userNew = await _userRepository.GetWhereAsync(x => x.Id == (int)newValue);var userOld = await _userRepository.GetWhereAsync(x => x.Id == (int)oldValue);changes.Add($"{propertyName}: [{userOld?.NickName}] => [{userNew?.NickName}]");}else{changes.Add($"{propertyName}: [{oldValue}] => [{newValue}]");}}
}var content = string.Join(",", changes);

在上面的示例中,FieldDescriptionAttribute 允许你为每个属性指定一个自定义的描述。在遍历属性时,使用 GetCustomAttributes 方法获取属性上的自定义属性,并从中获取描述信息,以替代默认的属性名作为变更内容的一部分。

这种方法能够使你的代码更具可读性和可维护性,特别是在处理需要详细描述的属性时。

方案四:获取summary备注

/// <summary>
/// 备注
/// </summary>

如果你希望在生成变更内容时,使用属性的 XML 注释(summary),或者自定义的备注信息作为字段的描述,可以结合使用反射和 XML 注释读取来实现。以下是一个示例:

首先,假设你的 ModelDto 类定义如下:

public class ModelDto
{/// <summary>/// 公司名称/// </summary>public string CompanyName { get; set; }/// <summary>/// 公司类型/// </summary>public CompanyType CompanyType { get; set; }/// <summary>/// 公司代码/// </summary>public string CompanyCode { get; set; }// 其他属性省略
}

然后,可以编写一个方法来获取属性的备注信息,优先使用 XML 注释(summary),如果没有 XML 注释则使用自定义的备注信息:

public static string GetPropertyDescription(PropertyInfo property)
{// 尝试获取 XML 注释(summary)var xmlComment = property.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false).FirstOrDefault() as System.ComponentModel.DescriptionAttribute;if (xmlComment != null){return xmlComment.Description;}// 如果没有 XML 注释,则使用属性名作为备注return property.Name;
}

最后,根据这个方法来生成变更内容:

var changes = new List<string>();var properties = typeof(ModelDto).GetProperties();foreach (var property in properties)
{var oldValue = property.GetValue(cusOld);var newValue = property.GetValue(modelDto);if (!Equals(oldValue, newValue)){var propertyName = GetPropertyDescription(property);// 特殊处理 SaleId 属性if (property.Name == "SaleId"){var userNew = await _userRepository.GetWhereAsync(x => x.Id == (int)newValue);var userOld = await _userRepository.GetWhereAsync(x => x.Id == (int)oldValue);changes.Add($"{propertyName}: [{userOld?.NickName}] => [{userNew?.NickName}]");}else{changes.Add($"{propertyName}: [{oldValue}] => [{newValue}]");}}
}var content = string.Join(",", changes);

在上面的示例中,GetPropertyDescription 方法会尝试从 XML 注释(summary)中获取属性的描述信息,如果找不到 XML 注释,则默认使用属性的名称。这样可以根据属性的描述信息生成更具描述性的变更内容。

这种方法结合了反射和 XML 注释读取,能够使你的代码更加灵活和可维护,特别是在需要生成详细变更日志或报告时非常有用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/46103.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分支定界法(Branch and Bound, 简称BB)是一种求解整数规划问题的有效算法。

分支定界法&#xff08;Branch and Bound&#xff09;详解与Python代码示例 分支定界法概述 分支定界法&#xff08;Branch and Bound, 简称B&B&#xff09;是一种求解整数规划问题的有效算法。它结合了搜索与迭代的思想&#xff0c;通过系统地枚举候选解来寻找最优解。在…

Java Web常见框架寻找路由技巧

在Java Web代码审计中&#xff0c;寻找和识别路由是很关键的部分。通过注册的路由可以找到当前应用对应的Controller&#xff0c;其作为MVC架构中的一个组件&#xff0c;可以说是每个用户交互的入口点。简单介绍下Java Web中常见框架&#xff08;Spring Web、Jersey&#xff09…

【SASS/SCSS(二)】模块化语法

目录 一、use 1、命名空间 2、私有变量 3、用with改变模块中的默认值 二、forward 1、给forward模块起别名&#xff0c;让成员加前缀 2、利用hide or show手动控制成员的可访问性 三、import 1、不存在命名空间&#xff0c;成员变量在import之后直接公开 2、可以在嵌…

springboot防止重复提交的方案有哪些

在Spring Boot中&#xff0c;防止接口或表单重复提交有多种策略&#xff0c;以下是几种常见且有效的方案&#xff1a; 前端控制&#xff1a; 禁用提交按钮&#xff1a;在表单提交后&#xff0c;使用JavaScript立即禁用提交按钮&#xff0c;防止用户再次点击。响应式提示&#x…

十、Java集合 ★ ✔(模块18-20)【泛型、通配符、List、Set、TreeSet、自然排序和比较器排序、Collections、可变参数、Map】

day05 泛型,数据结构,List,Set 今日目标 泛型使用 数据结构 List Set 1 泛型 1.1 泛型的介绍 ★ 泛型是一种类型参数&#xff0c;专门用来保存类型用的 最早接触泛型是在ArrayList&#xff0c;这个E就是所谓的泛型了。使用ArrayList时&#xff0c;只要给E指定某一个类型…

讲真,现在留给2024年下半年软考的时间还够吗?

常识是个好东西&#xff0c;但是有时候却容易蒙蔽咱们的双眼&#xff0c;就拿下半年软考而言&#xff0c;看起来现在才7月份&#xff0c;刚刚入伏&#xff0c;考试要到11月份&#xff0c;是冬天呢&#xff0c;中间还隔了一个完整的秋季&#xff0c;常识感觉还很遥远&#xff0c…

【Vue3】4个比较重要的设计模式!!

大家好,我是CodeQi! 一位热衷于技术分享的码仔。 在我投身于前端开发的职业生涯期间,曾有一次承接了一个大型项目的维护工作。此项目运用的是 Vue 框架,然而其代码结构紊乱不堪,可维护性极度糟糕😫。 这使我深刻领会到,理解并运用 Vue 中的重要设计模式是何等关键! …

对LinkedList ,单链表和双链表的理解

一.ArrayList的缺陷 二.链表 三.链表部分相关oj面试题 四.LinkedList的模拟实现 五.LinkedList的使用 六.ArrayList和LinkedList的区别 一.ArrayList的缺陷: 1. ArrayList底层使用 数组 来存储元素&#xff0c;如果不熟悉可以来再看看&#xff1a; ArrayList与顺序表-CSDN…

一些常见的网络故障

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 ☁️运维工程师的职责&#xff1a;监…

【数据分析】Python数据分析实战:从零开始构建数据管道

Python数据分析实战&#xff1a;从零开始构建数据管道 引言一、数据获取二、数据清洗三、数据分析四、数据可视化五、案例研究&#xff1a;预测股票价格结论 我尝试访问您所提供的链接&#xff0c;但似乎该链接指向的内容已失效或被移除&#xff0c;因此无法直接获取并阅读该文…

【iOS】——ARC源码探究

一、ARC介绍 ARC的全称Auto Reference Counting. 也就是自动引用计数。使用MRC时开发者不得不花大量的时间在内存管理上&#xff0c;并且容易出现内存泄漏或者release一个已被释放的对象&#xff0c;导致crash。后来&#xff0c;Apple引入了ARC。使用ARC&#xff0c;开发者不再…

BUUCTF逆向wp [HDCTF2019]Maze

第一步 查壳&#xff0c;本题是32位&#xff0c;有壳&#xff0c;进行脱壳。 第二步 这里的 jnz 指令会实现一个跳转&#xff0c;并且下面的0EC85D78Bh被标红了&#xff0c;应该是一个不存在的地址&#xff0c;这些东西就会导致IDA无法正常反汇编出原始代码&#xff0c;也称…

中文科技核心论文发表

中文科技核心论文题目如下&#xff1a; 1.混凝土结构用纤维增强塑料筋的耐久性评述&#xff1a;适合建筑、结构、材料等专业 2.建筑工程用阻燃塑料的研究进展&#xff1a;适合建筑、材料专业 3.纤维增强热塑性塑料在面部护具中的应用研究&#xff1a;适合化工、医学、材料等专…

springcloud2021.x使用nacos做配置中心

spirngcloud2021.0.5使用nacos做配置中心遇到的问题 环境 jdk1.8&#xff0c;spring-boot 2.6.13&#xff0c;spring-cloud-alibaba 2021.0.5.0 &#xff0c;spring-cloud 2021.0.5 方案一 application.properties # Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts…

C++中的condition_variable:条件变量

理解 C 中的条件变量&#xff08;Condition Variable&#xff09; 在多线程编程中&#xff0c;我们常常需要一个线程等待某个条件的变化&#xff0c;比如等待数据的生成或某个标志位的设置。如果没有条件变量&#xff08;condition_variable&#xff09;&#xff0c;线程可能会…

启智畅想火车类集装箱号码识别技术,软硬件解决方案

集装箱号码识别需求&#xff1a; 实时检测车皮号、火车底盘号码、集装箱号码&#xff0c;根据火车类型分为以下三种情况&#xff1a; 1、纯车皮&#xff0c;只检测车皮号&#xff1b; 2、火车拉货箱&#xff08;半车皮&#xff09;&#xff0c;检测车皮号集装箱号码&#xff1b…

如何从0搭建一个Ai智体day01

&#x1f4da;《AI破局行动&#xff5c;AI智能体&#xff08;coze&#xff09;实战手册》&#xff1a; https://d16rg8unadx.feishu.cn/wiki/XQESwHW5HiPFlrkZbkqc0Xp7nEb 说明 这个是授权访问的&#xff0c;想学习加我 微信/ Github:** watchpoints &#x1f4fa;Day1-大圣直播…

玩转HarmonyOS NEXT之常用布局三

轮播&#xff08;Swiper&#xff09; Swiper组件提供滑动轮播显示的能力。Swiper本身是一个容器组件&#xff0c;当设置了多个子组件后&#xff0c;可以对这些子组件进行轮播显示。通常&#xff0c;在一些应用首页显示推荐的内容时&#xff0c;需要用到轮播显示的能力。 针对…

git开发流程

分支介绍 master - 主分支 所有提供给用户使用的正式版本&#xff0c;都在这个主分支上发布 开发者在此分支 不可进行 push 操作 dev - 开发分支 日常开发所使用的分支&#xff0c;开发者完成的阶段性功能模块将首先被合并到此分支 此分支亦是团队内部测试、阶段性工作验证…

Xcode 16 beta3 真机调试找不到 Apple Watch 的尝试解决

很多小伙伴们想用 Xcode 在 Apple Watch 真机上调试运行 App 时却发现&#xff1a;在 Xcode 设备管理器中压根找不到对应的 Apple Watch 设备。 大家是否已将 Apple Watch 和 Mac 都重启一万多遍了&#xff0c;还是束手无策。 Apple Watch not showing in XCodeApple Watch wo…