我想通过自动从模型映射到视图模型。我的视图模型看起来像这样,模型(FooBarRecord
(几乎没有额外的属性,bar
属性是相同的:
public class FooBarVm
{
public int id { get; set; }
public BarRecord bar { get; set; }
public string foo { get; set; }
public id barbaz_id { get; set; }
public string barbaz_name { get; set; }
}
public class FooBarRecord
{
public int id { get; set; }
public BarRecord bar { get; set; }
public string foo { get; set; }
public int foo2 { get; set; }
public BarBazRecord barbaz { get; set; }
}
public class BarRecord
{
public int id { get; set; }
public BarBazRecord baz { get; set; }
public string bar1 { get; set; }
public int bar2 { get; set; }
}
public class BarBazRecord
{
public int id { get; set; }
public string name { get; set; }
}
问题出在条形列中。我的自动映射器配置如下所示:
Mapper.CreateMap<FooBarRecord, FooBarVm>()
.ForMember(s => s.bar, m => m.MapFrom(rec => rec.bar))
//other columns - those are OK
;
我也尝试了其他几种方法,比如定义从BarRecord
到BarRecord
的映射,或者用rec
代替rec.bar
和从FooBarRecord
映射到BarRecord
。我发现唯一可行的解决方案是展平BarRecord
,将其所有属性添加到FooBarVm
而不是单个引用 - 但这很丑陋且难以维护,绝对不是我想要的。
编辑:这些类只是示例,真实的类具有更多属性,但我已经检查过它们没问题。可能起到一定作用的是,在BarRecord
的属性中有一个对象,所以我将其添加为BarBazRecord
。
错误消息如下:
The following 4 properties on Foo.Bar.ViewModels.FooBarVm are not mapped:
bar1
bar2
id
name
这些都是BarRecord
和BarBazRecord
的非对象属性。我试图像这样解决它们:
.ForMember(s => s.bar.bar1, m => m.MapFrom(rec => rec.bar.bar1))
甚至忽略它们:
.ForMember(s => s.bar.bar1, opt => opt.Ignore())
但错误消息刚刚更改为"System.ArgumentException:表达式的 => s.poskytovatel.ulice' 必须解析为顶级成员。我确认工作的唯一解决方案是从第一条错误消息中添加整个列表(在我的真实情况下有数十个属性(,只是为了必须将代码从bar = vm.bar;
更改为bar = GetBar(vm.bar_id);
这是一种解决方法,但我更愿意学习适当的解决方案。
编辑2:即使解决方法也失败了:-(无论我做什么,我的第一个错误仍然存在。我将bar
更改为bar_id
将所有BarRecord
属性添加到FooBarVm
。然后我尝试映射新属性(m.MapFrom(rec => rec.bar.bar1)
(或忽略它们(opt => opt.Ignore()
(,甚至从FooBarVm
和自动映射器配置中删除对BarRecord
的任何引用。没有任何变化 - FooBarRecord
中不直接存在的所有属性都列为未映射,即使忽略或从嵌套模型中映射也是如此。向FooBarRecord
添加虚拟属性显然不是正确的方法,尽管这是证明会影响错误消息的唯一方法,除了用其他错误覆盖它。
我更新了模型 - BarBazRecord
也引用自FooBarRecord
,FooBarVm
包含从BarBazRecord
映射的属性。这些属性似乎映射正确,它们不包含在列表或未映射的属性中。那就更奇怪了。
我将其作为答案发布,因为它太大而无法发表评论。 在当前形式中,使用 Automapper 4.2,您的映射应该可以正常工作(见下文(。 我所做的唯一更改是将barbaz_id
定义为int
,而不是id
,以便编译代码。 因此,对于以下类型:
public class FooBarVm {
public int id { get; set; }
public BarRecord bar { get; set; }
public string foo { get; set; }
public int barbaz_id { get; set; }
public string barbaz_name { get; set; }
}
public class FooBarRecord {
public int id { get; set; }
public BarRecord bar { get; set; }
public string foo { get; set; }
public int foo2 { get; set; }
public BarBazRecord barbaz { get; set; }
}
public class BarRecord {
public int id { get; set; }
public BarBazRecord baz { get; set; }
public string bar1 { get; set; }
public int bar2 { get; set; }
}
public class BarBazRecord {
public int id { get; set; }
public string name { get; set; }
}
定义映射:
Mapper.CreateMap<FooBarRecord, FooBarVm>();
定义源:
var src = new FooBarRecord { bar = new BarRecord { bar1 = "b1", bar2 = 23,
baz = new BarBazRecord { id = 5,
name = "nme" },
id = 2 },
barbaz = new BarBazRecord { name = "nee",
id = 3 },
foo = "fooo", foo2 = 123, id = 99 };
并将其映射到目的地:
var dest = Mapper.Map<FooBarVm>(src);
所有字段均已映射,没有任何错误。 如果您正在做不同的事情,则应更新您的问题以使错误可重现。 或者,您可能需要检查是否使用的是最新版本的映射器。
问题出在另一个映射中,但我也需要稍后解决它。最后,正确使用ForAllMembers(opt => opt.Ignore()
起到了作用。
Mapper.CreateMap<FooBarRecord, FooBarVm>().ForAllMembers(opt => opt.Ignore());
Mapper.CreateMap<FooBarRecord, FooBarVm>()
.ForMember(s => s.bar, m => m.MapFrom(rec => rec.bar))
//other columns - those are OK
;