AutoMapper ProjectTo配置:为嵌套属性设置非空默认实例
问题:AutoMapper ProjectTo映射可选一对一关系时返回默认实例需求
环境
AutoMapper v8.1.1 / EF6
问题场景
使用ProjectTo映射可选一对一数据库关系时,当Owner.CarId为null,得到的OwnerDto.Car属性也为null。原本以为嵌套映射默认会返回新的CarDto实例,不确定该实例属性是取C#内置类型默认值(如int = 0)还是null,想知道能否在ProjectTo中实现类似.DefaultIfEmpty(new CarDto())的效果。
源类
public class Car { public int Id { get; set; } public string Model { get; set; } } public class Owner { public int Id { get; set; } public Car Car { get; set; } public int? CarId { get; set; } public string Name { get; set; } }
目标类
public class CarDto { public int Id { get; set; } public string Model { get; set; } } public class OwnerDto { public int Id { get; set; } public CarDto Car { get; set; } public int? CarId { get; set; } public string Name { get; set; } }
现有映射配置
new MapperConfiguration(settings => { settings.CreateMap<Owner, OwnerDto>(); settings.CreateMap<Car, CarDto>(); });
解决方案
方法1:直接在映射中添加条件判断(适配ProjectTo)
因为ProjectTo最终会转换为SQL查询,需确保逻辑能被EF解析。可以在Owner到OwnerDto的映射中,对Car字段做条件处理:
new MapperConfiguration(settings => { settings.CreateMap<Owner, OwnerDto>() .ForMember(dest => dest.Car, opt => opt.ResolveUsing(src => src.Car != null ? src.Car : new Car())); // 先返回默认Car实例,再自动映射为CarDto settings.CreateMap<Car, CarDto>(); });
此方式下,默认的Car实例会被AutoMapper转换为CarDto,其属性取C#内置默认值:值类型(如Id)为0,引用类型(如Model)为null。
方法2:自定义值解析器(适合复杂逻辑)
如果需要更灵活的默认值设置,可以自定义值解析器:
public class DefaultCarResolver : IValueResolver<Owner, OwnerDto, CarDto> { public CarDto Resolve(Owner source, OwnerDto destination, CarDto destMember, ResolutionContext context) { return source.Car != null ? context.Mapper.Map<CarDto>(source.Car) : new CarDto { Model = "无车辆" }; // 可自定义默认属性值 } }
然后在映射配置中引入:
new MapperConfiguration(settings => { settings.CreateMap<Owner, OwnerDto>() .ForMember(dest => dest.Car, opt => opt.MapFrom<DefaultCarResolver>()); settings.CreateMap<Car, CarDto>(); });
注意:解析器逻辑需能被AutoMapper转换为SQL表达式,避免客户端评估影响性能。简单的null判断和实例初始化可正常兼容ProjectTo。
方法3:AfterMap(仅内存映射生效)
如果是内存中直接映射(而非通过ProjectTo生成SQL查询),可以用AfterMap在映射完成后补全默认值:
new MapperConfiguration(settings => { settings.CreateMap<Owner, OwnerDto>() .AfterMap((src, dest) => { if (dest.Car == null) { dest.Car = new CarDto(); } }); settings.CreateMap<Car, CarDto>(); });
此方法不会影响ProjectTo生成的SQL,仅在数据加载到内存后执行替换操作。
内容的提问来源于stack exchange,提问作者crichavin
相关产品推荐
相关产品推荐

