如何使用自动映射器将简单的poco映射到复杂的对象层次结构?

Sli*_*ain 2 c# automapper

我有一个简单的poco,需要将其映射到由使用复杂对象层次结构的第三方提供的对象。我想尽可能使用AutoMapper,但不确定如何正确设置。

我在下面提供了一个简化的示例,以显示我要执行的操作。

我的poco:

public class Person
{
    public string FirstName { get; set; }
    public string Lastname { get; set; }
    public string FullName { get { return Firstname + " " + Lastname; } }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
    public string Postcode { get; set; }
    public string Reference { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

第三方对象

public class People
{
    public Person[] Person { get; set; }
}

public class Person
{
    public Names Names { get; set; }
    public Address Address { get; set; }
    public ReasonsForRequest[] Reasons { get; set; }
}

public class Names
{
    public string Fullname { get; set; }
}

public class Address
{
    public string AddressLine[] { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
    public string Postcode { get; set; }
}

public class ReasonsForRequest
{
    public StructuredReasons StructuredReasons { get; set; }
}

public class StructuredReasons
{
    public Reference Ref { get; set; }
}

public class Reference
{
    public string Ref { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是注册映射以获取引用映射。当我需要映射到内部对象和父对象时,如何将mappig注册到仅包含对象的对象?

ash*_*ber 5

[为清楚起见,我将称呼您的Person POCO PersonDTO,因为第三方代码也有一个名为的类Person

有两种方法可以做到这一点。我过去曾经使用过一个方法,其中涉及设置从PersonDTO到的映射Names,另一个从PersonDTO到的映射Address,以及从PersonDTO到的另一个映射Reasons。最后,从添加映射PersonDTOPerson。看起来像这样(我已经省略了Reasons,但您知道了):

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<PersonDTO, Names>()
        .ForMember(d => d.Fullname, o => o.MapFrom(s => s.FullName));
    cfg.CreateMap<PersonDTO, Address>()            
        .ForMember(d => d.AddressLine,
                o => o.MapFrom(s => new[] { s.AddressLine1, s.AddressLine2 }));
    cfg.CreateMap<PersonDTO, Person>()
        .ForMember(d => d.Names, o => o.MapFrom(s => s))
        .ForMember(d => d.Address, o => o.MapFrom(s => s));
});
var mapper = config.CreateMapper();

var myPerson = new PersonDTO() { 
    FirstName = "Bob", 
    LastName = "Gold",
    AddressLine1 = "123 Main Street", 
    AddressLine2 = "Apt. 2"
};

var theirPerson = mapper.Map<Person>(myPerson);
Run Code Online (Sandbox Code Playgroud)

但是最新版本的AutoMapper添加了一种ForPath()方法,该方法通过允许您访问内部对象来简化所有操作。现在,代码折叠为:

var config = new MapperConfiguration(cfg => 
    cfg.CreateMap<PersonDTO, Person>()
        .ForPath(d => d.Names.Fullname, o => o.MapFrom(s => s.FullName))
        .ForPath(d => d.Address.AddressLine, 
                o => o.MapFrom(s => new[]  { s.AddressLine1, s.AddressLine2 }))
);
var mapper = config.CreateMapper();
Run Code Online (Sandbox Code Playgroud)

编辑:我遗漏了一个方面,这可能会改变这两种方法之间的平衡。在第一种方法中,定义了多个映射,您将免费获得任何具有匹配名称的字段。例如,您不需要显式映射PesronDTO.CityAddress.City(如果将大小写更改PersonDTO.FullNamePersonDTO.Fullname,则也可以免费获取)。但是在第二种方法中,即使名称匹配,也必须显式映射所有嵌套字段。在您的情况下,我认为第一种方法可能对您更好,因为您只需显式地映射3个字段即可免费获得其他4个字段。对于第二种方法,您必须ForPath()对所有7个字段都执行一次。