嵌套映射AutoMapper扁平化要求自定义解析 [英] AutoMapper flattening of nested mappings asks for a custom resolver

查看:798
本文介绍了嵌套映射AutoMapper扁平化要求自定义解析的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有点新的AutoMapper,想要映射POCO十岁上下的对象或许是一个更复杂的DTO,后者试图成为一个重presentation的Google图书API的卷资源:

I'm somewhat new to AutoMapper and wanted to map a POCO-ish object to a perhaps more complex DTO, the latter tries to be a representation of a Google Books API's Volume resource:

Book.cs

public class Book
{
    public string Isbn10 { get; set; }
    public string Isbn13 { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
    public string Publisher { get; set; }
    public DateTime Publication { get; set; }
    public int Pages { get; set; }
    public string Description { get; set; }
    public bool InStock { get; set; }
}

BookDto.cs

public class BookDto
{
    public string Kind { get; set; }
    public string Id { get; set; }
    public VolumeInfo VolumeInfo { get; set; }
}

public class VolumeInfo
{
    public string Title { get; set; }
    public List<string> Authors { get; set; }
    public string Publisher { get; set; }
    public string PublishedDate { get; set; }
    public string Description { get; set; }
    public int PageCount { get; set; }
    public List<IndustryIdentifier> IndustryIdentifiers { get; set; }
}

public class IndustryIdentifier
{
    public string Type { get; set; }
    public string Identifier { get; set; }
}

所以,根据文档我们可以简单地拉平的嵌套式

AutoMapperConfigurator.cs

public static class AutoMapperConfigurator
{
    public static void Configure()
    {
        Mapper.CreateMap<Book, BookDto>()
            .ForMember(dto => dto.Id, options => options.Ignore())
            .ForMember(dto => dto.Kind, options => options.Ignore())
            .ForMember(dto => dto.VolumeInfo.Title, options => options.MapFrom(book => book.Title))
            .ForMember(dto => dto.VolumeInfo.Authors, options => options.MapFrom(book => book.Author.ToArray()))
            .ForMember(dto => dto.VolumeInfo.Publisher, options => options.MapFrom(book => book.Publisher))
            .ForMember(dto => dto.VolumeInfo.PublishedDate, options => options.MapFrom(book => book.Publication))
            .ForMember(dto => dto.VolumeInfo.Description, options => options.MapFrom(book => book.Description))
            .ForMember(dto => dto.VolumeInfo.PageCount, options => options.MapFrom(book => book.Pages))
            ;
    }
}

但运行 Mapper.AssertConfigurationIsValid()测试不幸的是,当我收到以下错误:

But unfortunately when running the Mapper.AssertConfigurationIsValid() Test I'm getting the following error:

System.ArgumentException : Expression 'dto => dto.VolumeInfo.Title'
must resolve to top-level member and not any child object's properties.
Use a custom resolver on the child type or the AfterMap option instead.
Parameter name: lambdaExpression 

所以,现在下这个建议与AfterMap尝试:

So now following that advice trying with AfterMap:

public static class AutoMapperConfigurator
{
    public static void Configure()
    {
        Mapper.CreateMap<Book, BookDto>()
            .ForMember(dto => dto.Id, options => options.Ignore())
            .ForMember(dto => dto.Kind, options => options.Ignore())
            .AfterMap((book, bookDto) => bookDto.VolumeInfo = new VolumeInfo 
                { 
                    Title = book.Title,
                    Authors = new List<string>(){ book.Author },
                    Publisher = book.Publisher,
                    PublishedDate = book.Publication.ToShortDateString(),
                    Description = book.Description,
                    PageCount = book.Pages
                });
    }
}

当再次运行测试,我现在收到这个讯息:

When running the test again I'm now getting this message:

Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, 
or modify the source/destination type
Book -> BookDto (Destination member list)
Dotnet.Samples.AutoMapper.Book -> Dotnet.Samples.AutoMapper.BookDto
(Destination member list)
VolumeInfo

我应该创建嵌套类的附加映射?任何指导,将真诚AP preciated,感谢很多提前。

Should I create additional mappings between the nested classes? Any guidance will be sincerely appreciated, thanks much in advance.

推荐答案

我做了使用.ForMember与用于VolumnInfo映射一个内部映射之前,类似的事情:

I've done something similar before using .ForMember with an internal mapping for the VolumnInfo mapping:

public static class AutoMapperConfigurator
{
    public static void Configure()
    {
        Mapper.CreateMap<Book, VolumeInfo>()
            .ForMember(dto => dto.Authors, options => options.MapFrom(book => book.Author.Split(',')))
            .ForMember(dto => dto.PublishedDate, options => options.MapFrom(book => book.Publication))
            .ForMember(dto => dto.PageCount, options => options.MapFrom(book => book.Pages))
            .ForMember(dto => dto.IndustryIdentifiers, options => options.Ignore());

        Mapper.CreateMap<Book, BookDto>()
            .ForMember(dto => dto.Id, options => options.Ignore())
            .ForMember(dto => dto.Kind, options => options.Ignore())
            .ForMember(dto => dto.VolumeInfo, options => options.MapFrom(book => Mapper.Map<Book, VolumeInfo>(book)));
    }
}

下面是几个单元测试,验证的功能:

Here are a couple of unit tests that verify the functionality:

[TestFixture]
public class MappingTests
{
    [Test]
    public void AutoMapper_Configuration_IsValid()
    {
        AutoMapperConfigurator.Configure();
        Mapper.AssertConfigurationIsValid();
    }

    [Test]
    public void AutoMapper_MapsAsExpected()
    {
        AutoMapperConfigurator.Configure();
        Mapper.AssertConfigurationIsValid();

        var book = new Book
            {
                Author = "Castle,Rocks",
                Description = "Awesome TV",
                InStock = true,
                Isbn10 = "0123456789",
                Isbn13 = "0123456789012",
                Pages = 321321,
                Publication = new DateTime(2012, 11, 01),
                Publisher = "Unknown",
                Title = "Why I Rock"
            };

        var dto = Mapper.Map<Book, BookDto>(book);

        Assert.That(dto.Id, Is.Null);
        Assert.That(dto.Kind, Is.Null);
        Assert.That(dto.VolumeInfo, Is.Not.Null);
        Assert.That(dto.VolumeInfo.Authors, Is.Not.Null);
        Assert.That(dto.VolumeInfo.Authors.Count, Is.EqualTo(2));
        Assert.That(dto.VolumeInfo.Authors[0], Is.EqualTo("Castle"));
        Assert.That(dto.VolumeInfo.Authors[1], Is.EqualTo("Rocks"));
        Assert.That(dto.VolumeInfo.Description, Is.EqualTo("Awesome TV"));
        Assert.That(dto.VolumeInfo.IndustryIdentifiers, Is.Null);
        Assert.That(dto.VolumeInfo.PageCount, Is.EqualTo(321321));
        Assert.That(dto.VolumeInfo.PublishedDate, Is.EqualTo(new DateTime(2012, 11, 01).ToString()));
        Assert.That(dto.VolumeInfo.Publisher, Is.EqualTo("Unknown"));
        Assert.That(dto.VolumeInfo.Title, Is.EqualTo("Why I Rock"));
    }
}

这篇关于嵌套映射AutoMapper扁平化要求自定义解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆