Automapper 返回一个空集合,我想要一个 null

问题描述 投票:0回答:7
public class Person
{
   Name { get; set; }
   IEnumerable<Address> Addresses { get; set; }
}

public class PersonModel
{
   Name { get; set; }
   IEnumerable<AddressModel> Addresses { get; set; }
}

如果我像这样将

Person
映射到
PersonModel

Mapper.DynamicMap<Person, PersonModel>(person);

如果

Addresses
上的
Person
属性为空,则它们在
PersonModel
上映射为空
Enumerable
而不是空值。

如何让

PersonModel
具有空的
Addresses
而不是空的
Enumerable

c# .net automapper
7个回答
77
投票

简单的答案是使用

AllowNullCollections

AutoMapper.Mapper.Initialize(cfg =>
{
    cfg.AllowNullCollections = true;
});

或者如果您使用实例 API

new MapperConfiguration(cfg =>
{
    cfg.AllowNullCollections = true;
}

24
投票

除了在

映射器配置初始化
中设置AllowNullCollections(如this answer中所述),您还可以选择在
AllowNullCollections
定义中设置
Profile
,如下所示:

public class MyMapper : Profile
{
    public MyMapper()
    {
        // Null collections will be mapped to null collections instead of empty collections.
        AllowNullCollections = true;

        CreateMap<MySource, MyDestination>();
    }
}

18
投票

所以可能有几种方法可以使用 Automapper 完成此操作,这只是其中一种:

Mapper.CreateMap<Person, PersonMap>()
   .AfterMap( (src, dest) => dest.Addresses = dest.Addresses?.Any() ? dest.Addresses : null );

此代码使用新的 c#

?.
运算符来实现空安全,因此如果您不能在代码中使用该功能,则可能需要删除它并检查是否为空。


3
投票

另一种替代方法是使用条件,因此仅在值不为空时映射值。 这可能需要该值默认为空(因为它不会被映射)

 Mapper.CreateMap<Person, PersonModel>()
.ForMember(
    dest => dest.Addresses,
    opt => opt => opt.Condition(source=> source.Addresses!= null));

1
投票

您应该能够为您想要此行为的属性定义自定义解析器。所以像:

Mapper.CreateMap<Address, AddressModel>();
Mapper.CreateMap<Person, PersonModel>()
    .ForMember(
        dest => dest.Addresses,
        opt => opt.ResolveUsing(person => person.Addresses.Any() ? person.Addresses.Select(Mapper.Map<Address, AddressModel>) : null));

1
投票

如果您希望将此作为 API 中的一般规则,您可以像这样在配置服务方法中配置 Automapper。

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors();
            services.AddControllers();
            [...]
            // configure automapping
            services.AddAutoMapper(cfg => cfg.AllowNullCollections = true, typeof(Startup));               
        }

或者,在单独的 DLL 中使用自动映射的情况下(例如:对于 DTO 服务),我更喜欢使用辅助函数,所以配置也应该在那里完成:

    public static class MappingHelper
    {
        private static readonly Lazy<IMapper> _lazy = new(() =>
        {
            var config = new MapperConfiguration(cfg =>
            {
                // This line ensures that internal properties are also mapped over.
                cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
                cfg.AddProfile<DomainToRepositoryProfile>();
                cfg.AddProfile<RepositoryToDomainProfile>();
                cfg.AllowNullCollections = true;
            });
            var mapper = config.CreateMapper();
            return mapper;
        });

        public static IMapper Mapper => _lazy.Value;
    }

0
投票

我无法使用 AutoMapper 12.0.1 和 Entity Framework Core 6.0.15 脚手架实体让 AllowNullCollections 与 net6 一起工作。唯一有效的方法是:

    internal class UserDtoMapper : Profile
    {
      public UserDtoMapper() 
      {
        CreateMap<User, UserDto>()
          .ForMember(dest => dest.Votes, 
              x => x.Condition(src => src.Votes != null && src.Votes.Any()))
          .ReverseMap();
      }
    }
    
    public partial class User 
    {
      // ... 
      public virtual ICollection<Vote> Votes { get; set; }
    }
    
    public class UserDto 
    {
      // ...
      public List<VoteDto>? Votes { get; set; }
    }
© www.soinside.com 2019 - 2024. All rights reserved.