AutoMapper.Collection - 如果源集合 属性 为空,则完全跳过映射

AutoMapper.Collection - Skip mapping entirely if source collection property is null

如果源集合 属性 为空,是否有任何方法可以让 AutoMapper.Collection 跳过集合的映射?

在我的例子中,客户端可能想向 API 发出信号,表明不需要更新给定的集合。一种合乎逻辑的方法是在客户端发送的 dto 中将集合 属性 设置为 null。

基本上:

在AutoMapper.Collection中有什么方法可以做到这一点吗?我要找的是这个:

// Sample Classes
public class Entity
{
    public ICollection<EntityChild> Children { get; set; }
}

public class EntityChild
{
    public int Id { get; set; }
    public string Value { get; set; }
}

public class Dto
{
    public ICollection<DtoChild> Children { get; set; }
}

public class DtoChild
{
    public int Id { get; set; }
    public string Value { get; set; }
}

// AutoMapper setup including equality for children
CreateMap<Dto, Entity>();
CreateMap<DtoChild, EntityChild>()
    .EqualityComparison((src, dst) => src.Id == dst.Id)
    .ReverseMap();

// Sample 1, null source collection
var entity = new Entity
{
    Children = new List<EntityChild>
    {
        new() { Id = 1, Value = "Value 1" },
        new() { Id = 2, Value = "Value 2" }
    }
};

var dtoSkipChildren = new Dto
{
    Children = null
};

// Since the source Children property is null, do not update the destination collection
mapper.Map(dtoSkipChildren, entity);

// Sample 2, empty source collection
entity = new Entity
{
    Children = new List<EntityChild>
    {
        new() { Id = 1, Value = "Value 1" },
        new() { Id = 2, Value = "Value 2" }
    }
};

var dtoClearChildren = new Dto
{
    Children = new List<DtoChild>()
};

// Now the source children is not null (but empty) so the destination collection should 
// be updated (in this case cleared since the source collection is empty)
mapper.Map(dtoClearChildren, entity);

AutoMapper.Collection 将空源 Children 属性 视为与包含空集合的源 Children 属性 相同。在这两种情况下,目标 Children 集合都会被清除。

我试图告诉 AutoMapper 跳过 source.Children 属性 if null:

CreateMap<Dto, Entity>()
    .ForMember(dst => dst.Children, opt => opt.Condition(src => null != src.Children));

这不会改变任何事情。同样在这种情况下,当 AutoMapper.Collection 设置为工作并且目标集合被清除时,源集合 属性 为空。

这也不是真正的解决方案:

CreateMap<Dto, Entity>()
    .ForMember(
        src => src.Children, 
        opt => opt.MapFrom((src, dst, _, ctx) => src.Children ?? ctx.Mapper.Map<ICollection<DtoChild>>(dst.Children)));

这意味着将目标集合反向映射到(空)源集合,因此可以映射回来。一个丑陋的骇客:

有没有人对如何实现这一点有建议 - 或者为什么我的用例不是一个好主意?

我遇到了同样的问题,我是这样想出来的

CreateMap<Dto, Entity>()
    .ForMember(
        dest=> dest.Children, 
        opt => {
                    opt.PreCondition(src =>src.Children!= null);
                    opt.MapFrom(src =>src.Children);

                });

然后在这个地方,你要使用映射写代码如下:

entity = mapper.Map<Dto, Entity>(dto , entity);

opt.PreCondition(src =>src.Children!= null) 基本上告诉 AutoMapper 如果源字段不为空则继续映射,否则不映射。

要阅读更多请看这个 https://docs.automapper.org/en/stable/Conditional-mapping.html#preconditions