使用automapper进行嵌套映射以收集对象

时间:2015-01-22 17:54:43

标签: c# nested automapper

我的对象结构是

Class cls1
{
    id,
    name,
    List<Address> address
}

Class cls2
{
    prop1,
    prop2,
    street,
    HouseNumber
}

我想将cls1映射到cls2,其中cls2.street应该使用Address对象的street属性进行映射。

当我尝试Mapper.CreateMap<cls1, cls2>().ForMember(gn => gn.Street, item => item.MapFrom(i => i.address. ...)时,它会显示为一个集合。 如何使用Automapper

解决此映射问题

1 个答案:

答案 0 :(得分:0)

cls2的每个实例代表一个地址,以及一些其他信息。 cls1的每个实例都有一个地址集合。因此,除非您假设每个cls1实例中只有一个地址,否则无法直接从cls1映射到cls2。

为了克服这个问题,通过引入表示地址加上其父cls1的非规范化对象,将单个cls1映射到多个cls2。然后映射可以从非规范化表示到cls2。

public class Cls1AndAddress
{
    public Cls1 Cls1;
    public Address Address;
}

[Test]
public void DenormalizationApproach()
{
    AutoMapper.Mapper.CreateMap<Cls1AndAddress, Cls2>()
        .ForMember(dest => dest.Prop1, opt => opt.MapFrom(src => src.Cls1.Name))
        .ForMember(dest => dest.Street, opt => opt.MapFrom(src => src.Address.Street))
        .ForMember(dest => dest.HouseNumber, opt => opt.MapFrom(src => src.Address.HouseNumber))
        ;

    var c1 = new Cls1
    {
        Addresses = new List<Address>
        {
            new Address {Street = "foo", HouseNumber = 1},
            new Address {Street = "bar", HouseNumber = 2},
        }
    };

    var denormalized = c1.Addresses.Select(address => new Cls1AndAddress {Cls1 = c1, Address = address});

    var c2 = AutoMapper.Mapper.Map<IEnumerable<Cls1AndAddress>, IEnumerable<Cls2>>(denormalized);

    var c2Array = c2.ToArray();
    Assert.AreEqual(2, c2Array.Length);
    Assert.AreEqual("foo", c2Array[0].Street);
    Assert.AreEqual("bar", c2Array[1].Street);
}

另一方面,如果每个cls1只有一个地址,您可以在映射中使用更直接的假设路径:

[Test]
public void AssumeSingleApproach()
{
    AutoMapper.Mapper.CreateMap<Cls1, Cls2>()
        .ForMember(dest => dest.Street, opt => opt.MapFrom(src => src.Addresses.Single().Street))
        .ForMember(dest => dest.HouseNumber, opt => opt.MapFrom(src => src.Addresses.Single().HouseNumber))
        ;

    var c1 = new Cls1
    {
        Addresses = new List<Address>
        {
            new Address {Street = "foo", HouseNumber = 1},
            // new Address {Street = "bar", HouseNumber = 2}, This would cause failure
        }
    };

    var c2 = AutoMapper.Mapper.Map<Cls1, Cls2>(c1);

    Assert.AreEqual(c2.Street, "foo");
}