从ProjectTo doesn’t support BeforeMap开始,如何将父对象传递给子对象集合?这是代码:
void Main()
{
Mapper.Initialize(c =>
{
c.AddProfile<Prof>();
});
myDbContext.Profiles
.ProjectTo<ProfileDto>()
.Dump(); // Linqpad Extension
}
public class Prof : Profile
{
public Prof()
{
CreateMap<ProfileEntity, ProfileDto>();
CreateMap<UserEntity, UserDto>();
}
}
public class ProfileDto
{
public string Name { get; set; }
public IEnumerable<UserDto> Users { get; set; }
}
public class UserDto
{
public string Name { get; set; }
public string ProfileName { get; set; }
}
我只想填写“ ProfileName”属性.
解决方法:
AutoMapper映射配置在单个(源,目标)级别上工作.我看不到将父级传递给子级源配置的任何方法.当然,您可以像在其他答案中一样使用全投影(LINQ Select),但是,如果要映射的对象包含许多属性,那么即使按惯例它们按名称匹配,这也会导致很多冗余代码.
想到的一种方法是使用中间投影将父项与子项配对:
class Prof : Profile
{
public Prof()
{
CreateMap<ProfileEntity, ProfileDto>()
.ForMember(dst => dst.Users, opt => opt.MapFrom(src =>
src.Users.Select(u => new { User = u, Profile = src })));
}
}
现在,AutoMapper Flattening功能将自动将source.Profile.Name映射到target.ProfileName.问题是主要属性(来自用户)不会被映射,因为它们在目标对象中没有前缀用户(例如UserName).我们可以通过定制Naming Convention解决此问题.将以下内容添加到项目中的新代码文件中:
using System;
using System.Collections.Generic;
using System.Reflection;
using AutoMapper.Configuration.Conventions;
using AutoMapper.Internal;
namespace AutoMapper.Configuration.Conventions
{
public class NameMatchMember : IChildMemberConfiguration
{
public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, LinkedList<MemberInfo> resolvers, IMemberConfiguration parent)
{
foreach (var memberInfo in sourceType.AllMembers)
{
if (!destType.Name.StartsWith(memberInfo.Name)) continue;
resolvers.AddLast(memberInfo);
var memberType = options.CreateTypeDetails(ReflectionHelper.GetMemberType(memberInfo));
if (parent.MapDestinationPropertyToSource(options, memberType, destType, destMemberType, nameToSearch, resolvers))
return true;
resolvers.RemoveLast();
}
return false;
}
}
}
namespace AutoMapper
{
public static class Extensions
{
public static IMemberConfiguration AddNameMatchMemberConvention(this IProfileExpression target) =>
target.AddMemberConfiguration().AddNameMatchMemberConvention();
public static IMemberConfiguration AddNameMatchMemberConvention(this IMemberConfiguration target) =>
target.AddMember<NameMatchMember>();
}
}
第一类实现自定义约定.对于未由其他约定映射的每个目标名称,它将尝试将其映射到作为目标类型名称前缀的源属性(例如,用户-> UserDto).
第二种只是将其添加到配置中的便捷方法.它可以在配置或概要文件级别上应用,但是为了对匿名类型产生影响,必须在配置级别上完成.
现在,您需要将其应用于您的配置:
Mapper.Initialize(c =>
{
c.AddNameMatchMemberConvention();
c.AddProfile(new Prof());
});
加上以上配置文件配置,就足以执行所需的映射.