.NET Core API更新对象时原加载对象被意外更新的问题
问题分析与解决方案
我之前也遇到过完全一样的问题!这是典型的引用类型传递导致的意外修改,咱们一步步拆解和解决:
问题根源
License是引用类型,当你把cLicense传给UpdateAsync方法时,传递的是对象的内存引用,而不是对象的副本。所以在UpdateAsync里直接修改cLicense的属性(比如cLicense.TypeId = nLicense.TypeId),本质上是直接修改了原对象的内存内容,自然外面的cLicense也跟着被修改了。
解决方案
有两种常用的思路来解决这个问题,根据你的代码场景选择即可:
方案1:深拷贝原对象,传递副本给UpdateAsync
在调用UpdateAsync之前,先创建cLicense的深拷贝,把副本传进去操作,这样原对象就能保持不变。
手动拷贝(适合属性较少的类)
// 在Update控制器里,获取原对象后先做拷贝 var cLicense = await _licenseService.GetAsync(groupId, licenseId); if (cLicense == null) return BadRequest(_localizer["LicenseNotExist"]); // 创建原对象的深拷贝 var licenseCopy = new License { Id = cLicense.Id, Group = cLicense.Group, // 如果Group也是引用类型,需要对Group也做嵌套拷贝 TypeId = cLicense.TypeId, DataLimit = cLicense.DataLimit, Email = cLicense.Email, Notes = cLicense.Notes, // 复制所有其他需要保留的原对象属性 }; // 传递副本给UpdateAsync var uLicense = await _licenseService.UpdateAsync(licenseCopy, _mapper.Map<License>(request));
序列化/反序列化拷贝(适合属性较多的类)
如果License类支持序列化,可以用这种快速实现深拷贝的方式:
using System.Text.Json; var cLicense = await _licenseService.GetAsync(groupId, licenseId); if (cLicense == null) return BadRequest(_localizer["LicenseNotExist"]); // 序列化再反序列化,生成完全独立的副本 var licenseCopy = JsonSerializer.Deserialize<License>(JsonSerializer.Serialize(cLicense)); var uLicense = await _licenseService.UpdateAsync(licenseCopy, _mapper.Map<License>(request));
方案2:修改UpdateAsync方法,避免直接修改传入的原对象
直接重构UpdateAsync,不在方法内修改传入的原对象,而是基于原对象创建新实例来操作:
public async Task<License> UpdateAsync(License originalLicense, License newLicense) { RSUser cRSUser = await _cloudService.GetCloudAsync(originalLicense.Group.Id); var result = await Task.Run(() => { // 基于原对象创建新的实例,应用新属性 var licenseToUpdate = new License { Id = originalLicense.Id, Group = originalLicense.Group, TypeId = newLicense.TypeId, DataLimit = newLicense.DataLimit, Email = newLicense.Email, Notes = newLicense.Notes, // 保留原对象的其他属性 }; if (licenseToUpdate.TypeId == 8) licenseToUpdate.DataLimit = 0; return cRSUser.updateLicense(licenseToUpdate.ToRSUserClass(), new List<RX_licensemode>() { new RX_licensemode() { P_id = newLicense.ProductId.ToString().ToUpper() } }); }); if (result != RSC_errorcode.success) return null; return await GetAsync(originalLicense.Group.Id, originalLicense.Id); }
这样原对象originalLicense完全不会被触碰,始终保持获取时的状态。
注意点
如果License包含嵌套的引用类型属性(比如Group),要确保深拷贝覆盖到所有嵌套对象,避免只拷贝了引用导致子对象被意外修改。
内容的提问来源于stack exchange,提问作者goldN
相关产品推荐
相关产品推荐

