C#中如何遍历对象仅更新修改字段?Entity Framework技术问询
问题与解决方案:Entity Framework仅更新变更字段实现
需求
需要遍历从数据库获取的实体objFromDb,对比DTO的字段差异,只修改objFromDb中发生变化的属性,让Entity Framework(EF)仅更新数据库中实际变更的字段。已知仅修改变更字段时EF会生成针对性的更新语句,但希望找到更灵活的实现方式,避免硬编码属性带来的维护成本。
现有代码问题
- 硬编码属性:当前代码逐个判断并赋值属性,当实体或DTO结构变更时,必须手动修改代码,灵活性差。
- 反射实现错误:尝试用反射遍历属性的代码存在语法错误,无法正确赋值。
- AutoMapper用法误解:直接将DTO映射后的实体赋值给
objFromDb,会导致EF失去对原跟踪实体的引用,无法识别变更。
解决方案
方案1:修复反射实现
通过反射遍历属性,对比值差异后仅更新变更字段,代码如下:
public T_IFS_EmployeeDTO Update(T_IFS_EmployeeDTO ojbDTO) { var objFromDb = _db.T_IFS_Employee.FirstOrDefault(u => u.EmployeeID == ojbDTO.EmployeeID); if (objFromDb != null) { var dbEntityType = objFromDb.GetType(); var dtoType = ojbDTO.GetType(); foreach (var dbProp in dbEntityType.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { // 跳过主键字段,避免修改 if (dbProp.Name == nameof(objFromDb.EmployeeID)) continue; // 获取DTO中对应的属性 var dtoProp = dtoType.GetProperty(dbProp.Name); if (dtoProp == null || !dbProp.CanWrite) continue; var dbValue = dbProp.GetValue(objFromDb); var dtoValue = dtoProp.GetValue(ojbDTO); // 对比属性值,不同则更新 if (!Equals(dbValue, dtoValue)) { dbProp.SetValue(objFromDb, dtoValue); } } // 无需调用Update,EF已跟踪objFromDb,修改属性会自动标记变更 _db.SaveChanges(); return _mapper.Map<T_IFS_Employee, T_IFS_EmployeeDTO>(objFromDb); } return ojbDTO; }
注意:使用Equals而非!=判断值差异,避免值类型装箱后出现的判断错误;跳过主键等不需要更新的字段;已跟踪的实体无需调用Update,否则会强制全字段更新。
方案2:AutoMapper映射到已跟踪实体(推荐)
利用AutoMapper的重载方法,直接将DTO属性映射到EF已跟踪的实体上,代码如下:
public T_IFS_EmployeeDTO Update(T_IFS_EmployeeDTO ojbDTO) { var objFromDb = _db.T_IFS_Employee.FirstOrDefault(u => u.EmployeeID == ojbDTO.EmployeeID); if (objFromDb != null) { // 将DTO属性映射到已存在的跟踪实体 _mapper.Map(ojbDTO, objFromDb); // EF自动检测变更,SaveChanges时仅更新修改过的字段 _db.SaveChanges(); return _mapper.Map<T_IFS_Employee, T_IFS_EmployeeDTO>(objFromDb); } return ojbDTO; }
优势:无需手动维护属性映射,AutoMapper会根据配置自动处理;EF能精准识别变更字段,生成最优的更新语句。
错误用法说明
你尝试的objFromDb = objFromCall代码无效,原因是:
objFromDb原本是EF上下文跟踪的实体,赋值后指向了一个未被跟踪的新对象objFromCall- EF无法识别新对象的变更,要么不生成更新语句,要么调用
Update后会强制更新所有字段,违背需求。
核心要点
- EF变更跟踪:当实体被上下文跟踪时,修改属性会自动标记为
Modified,SaveChanges仅更新变更字段。 - 避免滥用
Update:对已跟踪实体调用Update会将所有属性标记为变更,导致全字段更新,失去精准更新的意义。
内容的提问来源于stack exchange,提问作者Steve Cross
相关产品推荐
相关产品推荐

