当指定条件!= null时,Automapper无法正确映射null列表成员 [英] Automapper does not map properly null List member, when the condition != null is specified

查看:249
本文介绍了当指定条件!= null时,Automapper无法正确映射null列表成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑到我指定了以下内容,当我尝试映射对象的空列表(成员)时出现问题:

There is a problem when I try to map a null list (member) of an object, considering that I specified:

.ForAllMembers(opts => opts.Condition((src, dest, srcMember) =>
    srcMember != null
));
cfg.AllowNullCollections = true; // didn't help also

代码中的简短示例:

gi.PersonList = new List<Person>();
gi.PersonList.Add(new Person { Num = 1, Name = "John", Surname = "Scott" });
GeneralInfo gi2 = new GeneralInfo();
gi2.Qty = 3;

Mapper.Map<GeneralInfo, GeneralInfo>(gi2, gi);

gi.PersonList.Count = 0,该如何解决?

using System;
using System.Collections.Generic;
using AutoMapper;

public class Program
{
   public static void Main(string[] args)
    {
        Mapper.Initialize(cfg =>
        {
            cfg.AllowNullCollections = true;
            cfg.CreateMap<GeneralInfo, GeneralInfo>()
            .ForAllMembers(opts => opts.Condition((src, dest, srcMember) =>
                srcMember != null
            ));

        });
        GeneralInfo gi = new GeneralInfo();
        gi.Descr = "Test";
        gi.Dt = DateTime.Now;
        gi.Qty = 1;
        gi.PersonList = new List<Person>();
        gi.PersonList.Add(new Person { Num = 1, Name = "John", Surname = "Scott" });

        GeneralInfo gi2 = new GeneralInfo();
        gi2.Qty = 3;

        Console.WriteLine("Count antes de mapeo = " + gi.PersonList.Count);

        Mapper.Map<GeneralInfo, GeneralInfo>(gi2, gi);

        Console.WriteLine("Count despues de mapeo = " + gi.PersonList.Count);
        // Error : gi.PersonList.Count == 0 !!!! 
        //por que? si arriba esta: Condition((src, dest, srcMember) => srcMember != null ...

    }
}

class Person
{
    public int Num { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
}

class GeneralInfo
{
    public int? Qty { get; set; }
    public DateTime? Dt { get; set; }
    public string Descr { get; set; }
    public List<Person> PersonList { get; set; }
}

https://dotnetfiddle.net/N8fyJh

推荐答案

这应该可以,但是我不确定是否要像这样对它进行微管理:

This should work but I'm not sure if you want to micro manage it like that:

cfg.AllowNullCollections = true;
cfg.CreateMap<GeneralInfo, GeneralInfo>()
    .ForMember(x => x.PersonList, opts => opts.PreCondition((src) => src.PersonList != null));

问题是专门处理的集合(对于大多数映射器都是如此,尽管AutoMapper在这种情况下有点奇怪,这不是我的最爱),并且似乎需要初始化目标集合.正如我所看到的,收集并没有完整地复制,这是有道理的,但是您需要初始化并复制单个项目(这是我的推论,但听起来不错).

Problem is the collections that are handled specifically (that's true for most mappers though AutoMapper is a bit weird in this case, it's not my favorite) and seem to require the destination collection to be initialized. As I can see, collections are not copied in entirety which makes sense, but you need to initialize and copy individual items (this is my deduction but does sound right).

即即使您跳过源,目标仍将最终重新初始化(空).

I.e. even if you skip the source, destination would still end up reinitialized (empty).

问题似乎是Condition,因为文档,在以后的某个时间点应用,此时目的地已经初始化.

Problem as it seems is the Condition which is, given their documentation, applied at some later point, at which time the destination has already been initialized.

PreCondition具有与您期望的方式不同的签名,因为它不采用实际值,仅提供源.

PreCondition on the other hand has a different signature to be used like you intended, as it doesn't take actual values, just source is available.

唯一可行的解​​决方案是使用每个成员" PreCondition(如上所述).

The only solution that seems to work is to use "per member" PreCondition (like the above).

编辑:
...或这个(使用ForAllMembers),但是有点难看,反射等.

EDIT:
...or this (using the ForAllMembers), but a bit ugly, reflection etc.

cfg.CreateMap<GeneralInfo, GeneralInfo>()
.ForAllMembers(opts =>
    {
        opts.PreCondition((src, context) =>
        {
            // we can do this as you have a mapping in between the same types and no special handling
            // (i.e. destination member is the same as the source property)
            var property = opts.DestinationMember as System.Reflection.PropertyInfo;
            if (property == null) throw new InvalidOperationException();
            var value = property.GetValue(src);
            return value != null;
        });
    }
);

...但是似乎对此没有任何更清洁的支持.

...but there doesn't seem to be any cleaner support for this.

编辑(错误和最终想法):

从5.2.0#1918版本起,到现有集合的条件映射不起作用>

Conditional mapping to existing collection doesn't work from version 5.2.0 #1918

正如评论中指出的那样(@LucianBargaoanu),这似乎确实是一个错误,因为在这种拐角"情况下并不一致(尽管我不同意,这是一个非常典型的场景)收集并传递目的地.在这种情况下,由于目的地已经被初始化/清除,因此Condition几乎没有用.

As pointed out in the comment (by @LucianBargaoanu), this seems to be a bug really, as it's inconsistent in this 'corner' case (though I wouldn't agree on that, it's a pretty typical scenario) when mapping collections and passing the destination. And it pretty much renders the Condition useless in this case as the destination is already initialized/cleared.

确实唯一的解决方案似乎是PreCondition(但是由于签名不同而存在问题,我个人不确定为什么它们也不会将相同的过多参数传递给PreCondition? ).

The only solution indeed seems to be the PreCondition (but it has issues given the different signature, I'm personally not sure why they don't pass the same plethora of parameters into the PreCondition as well?).

还有更多信息:

相关代码(我认为)

使用条件"但未忽略#1940时巢嵌套已清除

尽管Condition()返回错误的#2111,但目标对象上的Collection属性仍被覆盖

空源集合清空目标集合#2031

这篇关于当指定条件!= null时,Automapper无法正确映射null列表成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆