我有一个对象树。我想用一些默认值更新对象,并扁平化一些属性。 但是,我不想创建新对象,只需更新现有树即可。 所以我想。好吧,我可以用大量的逻辑和递归来做到这一点。或者我可以用自动映射器尝试一下。基本上映射到自我。自动映射器可能会使用源更新目标。并执行奉承:
源/目标类型
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);
上面的代码将一个已经存在的Bar
的Foo
映射到另一个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 在集合之间映射时如何识别相同的元素。