Dot-Net
嵌套映射的 AutoMapper 展平需要自定義解析器
我對 AutoMapper 有點陌生,想將 POCO-ish 對象映射到可能更複雜的 DTO,後者試圖代表Google Books API 的 Volume資源:
圖書.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()測試時出現以下錯誤:System.ArgumentException:表達式 ‘dto => dto.VolumeInfo.Title’ 必須解析為頂級成員,而不是任何子對象的屬性。在子類型或 AfterMap 選項上使用自定義解析器。參數名稱:lambdaExpression
所以現在按照這個建議嘗試使用 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 }); } }再次執行測試時,我現在收到此消息:
未映射的成員被發現。查看下面的類型和成員。添加自定義映射表達式,忽略,添加自定義解析器,或修改源/目標類型 Book -> BookDto(目標成員列表) Dotnet.Samples.AutoMapper.Book -> Dotnet.Samples.AutoMapper.BookDto(目標成員列表)音量資訊
我應該在嵌套類之間創建額外的映射嗎?任何指導將不勝感激,在此先感謝。
在將 .ForMember 與 VolumnInfo 映射的內部映射一起使用之前,我已經做了類似的事情:
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))); } }以下是一些驗證功能的單元測試:
[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")); } }