自动映射器是否支持映射到自身并在同一对象上平坦/执行映射



我有一个对象树。我想用一些默认值更新对象,并扁平化一些属性。 但是,我不想创建新对象,只需更新现有树即可。 所以我想。好吧,我可以用大量的逻辑和递归来做到这一点。或者我可以用自动映射器尝试一下。基本上映射到自我。自动映射器可能会使用源更新目标。并执行奉承:

源/目标类型

public class Foo
{
public bool SomeBool { get; set; }
public IEnumerable<Bar> Bars { get; set; }
}

public class Bar
{
public bool SomeBoolWithDefalting { get; set; }
}

映射配置

var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Foo, Foo>();
cfg.CreateMap<Bar, Bar>()
.ForMember(dest => dest.SomeBoolWithDefalting, opt=>opt.MapFrom(src=>true));
});
var mapper = config.CreateMapper();
var foo = new Foo
{
Bars = new List<Bar> { new Bar() }
};
mapper.Map<Foo, Foo>(foo, foo);

版本:

9.0.0

预期行为

我希望柱线会用默认值更新。而 foo 和酒吧和以前是同一个对象

实际行为

但我得到的只是空酒吧。

如果我:

var newFoo = mapper.Map<Foo, Foo>(foo);

然后我得到一个新的foo,条形图更新了。

我知道应该使用自动映射器来制作新对象。但事实并非如此。用例有效吗?只在目的地表现讨人喜欢?

重现步骤


class Program
{
static void Main(string[] args)
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Foo, Foo>();
cfg.CreateMap<Bar, Bar>()
.ForMember(dest => dest.SomeBoolWithDefalting, opt => opt.MapFrom(src => true));
});
var mapper = config.CreateMapper();
var foo = new Foo
{
Bars = new List<Bar> { new Bar() } 
};
var newFoo = mapper.Map<Foo, Foo>(foo); //good bars, but new objects
mapper.Map<Foo, Foo>(foo, foo); //same foo, but no bars
Console.WriteLine(foo.Bars.First().SomeBoolWithDefalting);
}
}

简短回答:映射到现有集合时,AutoMapper 首先清除目标集合。

<小时 />

解释

让我们向Bar类添加一个Name属性:

public class Bar
{
public string Name { get; set; }
public bool SomeBoolWithDefalting { get; set; }
}

然后运行下面的映射代码段:

var newFoo = new Foo
{
Bars = new List<Bar>
{
new Bar
{
Name = "Bar that will be mapped.",
},
},
};
var notEmptyFoo = new Foo()
{
Bars = new List<Bar>
{
new Bar
{
Name = "Bar that will be removed.",
}
},
};
Console.WriteLine(notEmptyFoo.Bars.First().Name);
mapper.Map<Foo, Foo>(newFoo, notEmptyFoo);
Console.WriteLine(notEmptyFoo.Bars.First().Name);

上面的代码将一个已经存在的BarFoo映射到另一个Foo也具有已经存在的Bar。但是AutoMapper会在映射过程开始之前从目标Foo(在代码段notEmptyFoo中命名(中删除所有Bar

控制台输出将显示:

Bar that will be removed.
Bar that will be mapped.

因此,当您从同一Foo映射到同一时,不仅在映射之前清除了目标Foo条形图,而且源Foo以及它是相同的,并且是一个Foo对象!因此,清除后,源Foo中没有条形图可以映射,因为它刚刚被清除。

如果要保留目标集合的元素,请查看 AutoMapper.Collection 项目。在那里,您可以设置一个 EqualComparison,告诉 AutoMapper 在集合之间映射时如何识别相同的元素。

最新更新