c# - Automapper - 使 IncludeMembers() 忽略 null
问题描述
IncludeMembers()
即使 object 是 ,也将始终从第一个匹配项映射null
。
假设我们有以下源模型:
public class Item
{
public MovieMetadata MovieMetadata { get; set; }
public BookMetadata BookMetadata { get; set; }
}
public class MovieMetadata
{
public string Title { get; set; }
}
public class BookMetadata
{
public string Title { get; set; }
}
目的地型号:
public class ItemDetail
{
public string Title { get; set; }
}
映射配置文件:
public class ItemProfile : Profile
{
public ItemProfile()
{
CreateMap<Item, ItemDetail>()
.IncludeMembers(
src => src.BookMetadata,
src => src.MovieMetadata);
CreateMap<BookMetadata, ItemDetail>();
CreateMap<MovieMetadata, ItemDetail>();
}
}
以及具有实例化和测试逻辑的 Program 类:
public class Program
{
public static void Main()
{
//create mapper
var configuration = new MapperConfiguration(cfg =>
{
cfg.AddMaps(typeof(ItemProfile));
});
var mapper = configuration.CreateMapper();
//check if configuration valid
mapper.ConfigurationProvider.AssertConfigurationIsValid();
Console.WriteLine("Mapper configuration is valid");
//try map book metadata
var bookItem = new Item
{
BookMetadata = new BookMetadata()
{
Title = "book"
},
MovieMetadata = null
};
var bookItemDetail = mapper.Map<ItemDetail>(bookItem);
bool isBookCorrectlyMapped = bookItem.BookMetadata.Title == bookItemDetail.Title;
Console.WriteLine($"Book mapped correctly: {isBookCorrectlyMapped}");
//try map movie metadata
var movieItem = new Item
{
BookMetadata = null,
MovieMetadata = new MovieMetadata()
{
Title = "movie"
}
};
var movieItemDetail = mapper.Map<ItemDetail>(movieItem);
bool isMovieCorrectlyMapped = movieItem.MovieMetadata.Title == movieItemDetail.Title;
Console.WriteLine($"Movie mapped correctly: {isMovieCorrectlyMapped}");
}
}
这是我们将看到的输出:
Mapper configuration is valid
Book mapped correctly: True
Movie mapped correctly: False
我们看到BookMetadata
成功的项目映射,但MovieMetadata
失败的映射。需要进行更新,以便此测试成功。
假设它失败的原因是因为项目的顺序IncludeMembers()
:
.IncludeMembers(
src => src.BookMetadata,
src => src.MovieMetadata)
这里我们有src.BookMetadata
第一和src.MovieMetadata
第二。在映射过程中,它会在其中找到Title
字段src.BookMetadata
并始终使用该值,即使src.BookMetadata
是null
。
有没有办法跳过src.BookMetadata
它null
并使用 nextsrc.MovieMetadata
代替?或者可能需要使用其他东西而不是IncludeMembers()
?
这是类似的问题:https ://github.com/AutoMapper/AutoMapper/issues/3204
您可以在此处找到上面的代码以快速重现问题:https ://dotnetfiddle.net/9YLGR6
解决方案
找到了可能的解决方案。
选项 1. IValueResolver
我们可以创建自定义值解析器。此解决方案适用于我们需要从子对象映射的少量字段。因为任何字段都需要特定的值解析器。
让我们创建TitleResolver
:
public class TitleResolver : IValueResolver<Item, ItemDetail, string>
{
public string Resolve(Item source, ItemDetail destination, string destMember, ResolutionContext context)
{
if (source != null)
{
if (source.BookMetadata != null)
{
return source.BookMetadata.Title;
}
if (source.MovieMetadata != null)
{
return source.MovieMetadata.Title;
}
}
return null;
}
}
并更新ItemProfile
:
public class ItemProfile : Profile
{
public ItemProfile()
{
CreateMap<Item, ItemDetail>()
.ForMember(dest => dest.Title, opt => opt.MapFrom<TitleResolver>());
}
}
链接到整个代码示例:https ://dotnetfiddle.net/6pfKYh
选项 2.BeforeMap()/AfterMap()
如果我们的子对象有多个字段要映射到目标对象,那么使用BeforeMap()
或AfterMap()
方法可能是一个好主意。在这种情况下,ItemProfile
将更新为:
public class ItemProfile : Profile
{
public ItemProfile()
{
CreateMap<Item, ItemDetail>(MemberList.None)
.AfterMap((src, dest, ctx) =>
{
if (src.BookMetadata != null)
{
ctx.Mapper.Map(src.BookMetadata, dest);
}
else if (src.MovieMetadata != null)
{
ctx.Mapper.Map(src.MovieMetadata, dest);
}
});
CreateMap<BookMetadata, ItemDetail>();
CreateMap<MovieMetadata, ItemDetail>();
}
}
链接到整个代码示例:https ://dotnetfiddle.net/ny1yRU
推荐阅读
- vue.js - 在自定义组件上使用 v-for,我可以访问组件内部的 ":key" 的值吗?
- api - WeatherStack 在 Flutter 中无法正常工作
- python - 从 JSON 文件中的字典列表返回值
- ios - iOS:带有 SO_REUSEPORT 的套接字不接收所有多播数据包
- java - Spring Boot 从 2.2.x 升级到 2.4.x:@Test 不再可以通过 application.properties 中的@activatedProperties@ 访问活动配置文件
- python - 以 utf-8 将 unicode 字符打印到终端
- javascript - Webpack 5 (Webpack Encore):如何在同一页面上运行多个 webpack 实例并避免任何冲突?
- javascript - javascript: input a txt file to create an array and output its containt in html
- c++ - Create a new vector with some indices, potentially non-consecutive, dropped
- html - Href 仅在单击 div 文本而不是整个 div 时有效