AutoMapper使用Ignore方法时目标属性被设为null的问题排查
AutoMapper Ignore方法导致目标属性被设为null的问题分析
我尝试用AutoMapper的Ignore()方法忽略目标属性,以保留它的原始值,多数情况这个方法有效,但有时会把目标属性值设为null。以下是复现代码,预期client.ContactDetails.First().Address的值为“Old”:
using AutoMapper; class Program { static void Main(string[] args) { ClientMapperProfile clientMapperProfile = new ClientMapperProfile(); var configurationProvider = new MapperConfiguration(c => c.AddProfile(clientMapperProfile)); Mapper mapper = new Mapper(configurationProvider); var client = new Client() { ContactDetails = new [] { new ContactDetails() { Address= "Old" } } }; var clientDto = new ClientDto() { ContactDetails = new [] { new ContactDetailsDto() { Address = "New" } } }; mapper.Map(clientDto,client); Console.WriteLine(client.ContactDetails.First().Address); } } public class Client { public ContactDetails[] ContactDetails { get; set; } } public class ContactDetails { public string Address { get; set; } } public class ClientDto { public ContactDetailsDto[] ContactDetails { get; set; } } public class ContactDetailsDto { public string Address { get; set; } } public class ClientMapperProfile : Profile { public ClientMapperProfile() { CreateMap<ClientDto, Client>(); CreateMap<ContactDetailsDto, ContactDetails>() .ForMember(c => c.Address, opt => opt.Ignore()); } }
问题原因
核心问题出在AutoMapper对数组类型属性的默认映射逻辑:
AutoMapper处理数组时,默认会创建一个全新的数组实例,替换掉目标对象中原有的数组。也就是说,client.ContactDetails会被替换成新的ContactDetails[],这个新数组里的ContactDetails对象是全新生成的——虽然你对Address设置了Ignore(),但新对象的Address本身就是默认的null,最终输出自然是null,而非原有的“Old”。
解决方案
方案1:配置集合映射保留目标实例
修改ClientDto到Client的映射,使用UseDestinationValue()让AutoMapper复用目标端原有的数组实例,只对数组内的元素进行属性映射:
public class ClientMapperProfile : Profile { public ClientMapperProfile() { CreateMap<ClientDto, Client>() .ForMember(dest => dest.ContactDetails, opt => opt.UseDestinationValue()); CreateMap<ContactDetailsDto, ContactDetails>() .ForMember(c => c.Address, opt => opt.Ignore()); } }
方案2:改用List替代数组
AutoMapper对List<T>的默认处理逻辑是复用目标集合实例,仅更新集合内的元素属性。将代码中的数组类型替换为List即可:
// 修改Client类 public class Client { public List<ContactDetails> ContactDetails { get; set; } } // 修改ClientDto类 public class ClientDto { public List<ContactDetailsDto> ContactDetails { get; set; } } // 实例化时对应修改为List var client = new Client() { ContactDetails = new List<ContactDetails>() { new ContactDetails() { Address= "Old" } } }; var clientDto = new ClientDto() { ContactDetails = new List<ContactDetailsDto>() { new ContactDetailsDto() { Address = "New" } } };
验证效果
采用任意一种方案修改后,运行代码,client.ContactDetails.First().Address会输出预期的“Old”。
内容的提问来源于stack exchange,提问作者Thiago
相关产品推荐
相关产品推荐

