6

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

.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

4

2 回答 2

7

这应该可行,但我不确定您是否想像这样对其进行微管理:

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

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

即,即使您跳过源,目标仍然会重新初始化(空)。

问题似乎是Condition,鉴于他们的文档,在稍后的某个时间点应用,此时目的地已经被初始化。

PreCondition另一方面,可以像您预期的那样使用不同的签名,因为它不采用实际值,只有源可用。

似乎唯一可行的解​​决方案是使用“每个成员” PreCondition(如上)。


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

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;
        });
    }
);

...但似乎没有任何更干净的支持。


编辑(错误和最终想法)

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

正如评论中所指出的(@LucianBargaoanu),这似乎真的是一个错误,因为在映射集合和传递时,在这个“角落”案例中它是不一致的(尽管我不同意,这是一个非常典型的场景)目的地。Condition在这种情况下,由于目的地已经初始化/清除 ,它几乎使无用的。

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

还有更多信息:

相关代码(我认为)

使用 Condition 但不是 Ignore 时,嵌套集合清晰 #1940

尽管 Condition() 返回 false,但目标对象上的集合属性被覆盖 #2111

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

于 2017-12-16T20:47:56.020 回答
1

试试这样;

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

我最近遇到了这个问题,不知何故,如果目标和源是同一类型,目标参数就不能按预期工作。

Collection另外,我想通知它与对象无关。如果您调试gi对象,您将看到其他属性也保留旧值。Automapper如果您将目标实例作为目标参数传递,则不会以某种方式更改之前分配的属性值。我认为,主要Automapper不是为创建复制/克隆对象而设计的。

于 2017-12-15T15:41:48.593 回答