AutoMapper:映射记录类型问题

ife*_*lif 22 c# automapper

我正在使用此类中的 c# 9 中的 automapper 10.1.1 进行映射

public record BFrom 
{
    public Guid Id { get; init; }
    public Guid DbExtraId { get; init; }
}
Run Code Online (Sandbox Code Playgroud)

进入这个

public record ATo(Guid Id, Guid ExtraId) : BaseTo(Id);
Run Code Online (Sandbox Code Playgroud)

并有以下配置

CreateMap<BFrom, ATo>()
    .ForMember("ExtraId", opt => opt.MapFrom(src => src.DbExtraId))
    .ReverseMap();
Run Code Online (Sandbox Code Playgroud)

但是当我尝试映射时,我遇到了一个问题,它抛出一个异常,并显示一条消息,该消息需要有一个带有 0 个参数或只有可选参数的构造函数。是否可以在不更改记录类型的情况下解决此问题?

fro*_*hli 11

您需要的是在映射配置文件中按名称指定构造函数参数,这样public AToProfile() => CreateMap<BFrom, ATo>().ForCtorParam(ctorParamName: "ExtraId", m => m.MapFrom(s => s.DbExtraId)).ReverseMap();,AutoMapper 就会知道应该从哪里获取值并进行相应的映射。

public class StackoverflowQuestionTest
{
    [Fact]
    public void BFrom_MapTo_ATo()
    {
        // Arrange
        IConfigurationProvider configuration = new MapperConfiguration(cfg => cfg.AddProfile<AToProfile>());
        var source = new BFrom {Id = Guid.NewGuid()};

        // Act
        var target = new Mapper(configuration).Map<ATo>(source);

        // Assert
        target.Id.Should().Be(source.Id);
    }


}

public record BaseTo (Guid Id); // this is an assumption, as you did not specify BaseTo in you question

public record BFrom
{
    public Guid Id { get; init; }
    public Guid DbExtraId { get; init; }
}

public record ATo(Guid Id, Guid ExtraId) : BaseTo(Id);

public class AToProfile : Profile
{
    public AToProfile() =>
        CreateMap<BFrom, ATo>()
            .ForCtorParam(ctorParamName: "ExtraId", m => m.MapFrom(s => s.DbExtraId))
            .ReverseMap();
}
Run Code Online (Sandbox Code Playgroud)


Chr*_*nne 9

我遇到了同样的问题,最终创建了这个扩展方法来解决它:

public static class AutoMapperExtensions
{
    public static IMappingExpression<TSource, TDestination> MapRecordMember<TSource, TDestination, TMember>(
        this IMappingExpression<TSource, TDestination> mappingExpression,
        Expression<Func<TDestination, TMember>> destinationMember, Expression<Func<TSource, TMember>> sourceMember)
    {
        var memberInfo = ReflectionHelper.FindProperty(destinationMember);
        string memberName = memberInfo.Name;
        return mappingExpression
            .ForMember(destinationMember, opt => opt.MapFrom(sourceMember))
            .ForCtorParam(memberName, opt => opt.MapFrom(sourceMember));
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你只需像这样使用它:

CreateMap<BFrom, ATo>()
    .MapRecordMember(a => a.ExtraId, src => src.DbExtraId)
    .ReverseMap();
Run Code Online (Sandbox Code Playgroud)

并且它将负责注册构造函数和成员,这样您就不会遇到此类问题。


Ath*_*ras 3

尝试

CreateMap<BFrom, ATo>().DisableCtorValidation()
    .ForMember("ExtraId", opt => opt.MapFrom(src => src.DbExtraId))
    .ReverseMap()
Run Code Online (Sandbox Code Playgroud)

  • 但是如果想让AutoMapper构造一个新的`ATo`就不行了?即 `mapper.Map&lt;ATo&gt;(new BFrom(...))` 失败并显示“需要有一个带有 0 个参数或只有可选参数的构造函数...” (2认同)