自动映射从源和输出引用的同一模型的对象

Automapping objects of the same model referenced from both source and output

我想通过自动映射从模型到视图模型。我的视图模型看起来像这样,模型 (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
;

我还尝试了一些其他方法,比如定义从 BarRecordBarRecordsubstitution of rec for rec.bar and mapping from FooBarRecord to BarRecord 的映射。我发现唯一可行的解​​决方案是展平 BarRecord,将其所有属性添加到 FooBarVm 而不是单个引用 - 但这很丑陋且难以维护,绝对不是我想要的。

编辑:类 只是示例,真实的有更多属性,但我已经检查过它们没问题。可能有点作用的是BarRecord的属性中有一个对象,所以我把它加成BarBazRecord.

错误信息如下:

The following 4 properties on Foo.Bar.ViewModels.FooBarVm are not mapped:
bar1
bar2
id
name

这些都是BarRecordBarBazRecord的非对象属性。我试着这样解决它们:

.ForMember(s => s.bar.bar1, m => m.MapFrom(rec => rec.bar.bar1))

甚至忽略它们:

.ForMember(s => s.bar.bar1, opt => opt.Ignore())

但错误消息刚刚更改为 "System.ArgumentException: Expression 's => s.poskytovatel.ulice' must resolve to top-level member." 我确认有效的唯一解决方案是从第一个错误消息(在我的实际情况中有数十个属性)添加整个列表,只需更改代码比如从 bar = vm.bar;bar = GetBar(vm.bar_id); 这是一个解决方法,但我更愿意学习一个合适的解决方案。

EDIT2:即使解决方法失败了:-(无论我做什么,我的第一个错误仍然存​​在。我将 bar 更改为 bar_id 添加所有 BarRecord 属性FooBarVm。然后我尝试映射新属性 (m.MapFrom(rec => rec.bar.bar1)) 或忽略它们 (opt => opt.Ignore()),甚至从 [=24= 中删除对 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);

所有字段都已映射,没有任何错误。如果您正在做一些不同的事情,您应该更新您的问题以使错误可重现。或者,您可能想检查您是否使用了最新版本的映射器。

问题出在另一个映射中,但我也需要解决它,只是稍后。最后,correct use of 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
;