如何在AutoMapper更新时保留集合对象的未映射属性?
问题:AutoMapper更新时保留集合对象的自定义属性
场景说明
我有一个源对象和目标对象,两者都包含Elements集合。使用AutoMapper将源对象映射到目标对象后,我给目标对象独有的属性ItemName、ItemNumber赋值,同时给AssetElementDto集合内对象的Text属性赋值。之后调用mapper.Map(source_update, destination);更新目标对象。
遇到的问题
运行代码后,ItemName和ItemNumber的信息在更新后得以保留,但AssetElementDto的Text信息丢失了,如何让该属性也保留?
示例代码
using AutoMapper; using System.Runtime.InteropServices; public class Program { static void Main(string[] arg) { var config = new MapperConfiguration(cfg => { cfg.CreateMap<Source, Destination>().PreserveReferences(); cfg.CreateMap<AssetElement, AssetElementDto>().PreserveReferences(); }); var mapper = new Mapper(config); var source = new Source() { Name = "Sinonis", Id = new Random().Next(), Elements = new List<AssetElement> { new(){ Id = 1}, new(){ Id = 2} } }; var destination = mapper.Map<Destination>(source); destination.ItemNumber = 42; destination.Elements.ForEach(e => e.Text ="Wow"); destination.ItemName = "NPC21"; var source_update = new Source() { Name = "Nindalf", Id = new Random().Next(), Elements = new List<AssetElement> { new(){ Id = 3}, new(){ Id = 4} } }; Console.WriteLine($"Before update is: {destination.Name} {destination.Id} {destination.ItemNumber} {destination.ItemName}"); destination.Elements.ForEach(e => Console.WriteLine($" {e.Id} {e.Text}")); mapper.Map(source_update, destination); Console.WriteLine($"After update is : {destination.Name} {destination.Id} {destination.ItemNumber} {destination.ItemName}"); destination.Elements.ForEach(e => Console.WriteLine($" {e.Id} {e.Text}")); } } #region Source public class Source { public string Name; public int Id; public List<AssetElement> Elements; } public class AssetElement { public int Id; } #endregion #region Destination public class Destination { public string Name; public int Id; public List<AssetElementDto> Elements; public int ItemNumber; public string ItemName; } public class AssetElementDto { public string Text; public int Id; } #endregion
控制台输出
Before update is: Sinonis 1643275093 42 NPC21 1 Wow 2 Wow After update is : Nindalf 75522068 42 NPC21 3 null 4 null
可以看到Wow在更新后未被保留。
解决方案
要保留Text属性,需要配置AutoMapper对集合执行合并更新而非完全替换,同时指定集合对象的匹配规则,让AutoMapper找到已存在的目标对象并更新,而非创建新对象。具体实现如下:
修改Mapper配置
var config = new MapperConfiguration(cfg => { cfg.AddCollectionMappers(); // 启用AutoMapper内置集合映射器 cfg.CreateMap<Source, Destination>().PreserveReferences(); cfg.CreateMap<AssetElement, AssetElementDto>() .EqualityComparison((src, dest) => src.Id == dest.Id) // 用Id作为集合元素的匹配依据 .ForMember(dest => dest.Text, opt => opt.UseDestinationValue()); // 保留目标对象的Text属性值 });
原理说明
UseDestinationValue():告诉AutoMapper在更新时,目标对象的Text属性保持现有值,不被源对象(无Text属性,默认会设为null)覆盖。EqualityComparison:指定集合元素的匹配规则,让AutoMapper能匹配源和目标集合中Id相同的元素,执行属性更新而非直接替换整个集合。AddCollectionMappers():启用AutoMapper的集合合并逻辑,避免直接替换目标集合。
内容的提问来源于stack exchange,提问作者Nindalf
相关产品推荐
相关产品推荐

