【问题标题】:How to map a child with automapper and convert using如何使用自动映射器映射孩子并使用转换
【发布时间】:2020-04-22 14:36:27
【问题描述】:

我正在使用 automapper 从模型映射到 dto。在我的模型中,我想使用一个字符串,在我的 dto 中我使用一个枚举。虽然它是一个嵌套的孩子,但我使用的是 ForPath 而不是 ForMember。转换为字符串很容易,但是将字符串转换回类型我写了一个 ValueConverter。将 ValueConverter 与 ForMember 结合使用效果很好,但是现在我需要将它与 ForPath 一起使用,这是不可能的。是否有任何其他解决方案可以解决此问题,而我在 automapper 文档或堆栈中找不到它。

这是我的映射配置文件 这部分正在与成员合作:

CreateMap<Dto, Model>()
            .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.Type.ToString()))
            .ReverseMap()
            .ForMember(dest => dest.Type, opt => opt.ConvertUsing(new StringToEnumConverter<Type>(), src => src.Type));

这部分我需要ForPath和ConvertUsing,这段代码是不允许的

    CreateMap<Dto, Model>()
            .ForPath(dest => dest.Type, opt => opt.MapFrom(src => src.Parent.Type.ToString()))
            .ReverseMap()
            .ForPath(dest => dest.Parent.Type, opt => opt.ConvertUsing(new StringToEnumConverter<Type>(), src => src.Type));

这是我的 ValueConverter:

public class StringToEnumConverter<T> : IValueConverter<string, T> where T : struct
{
    public T Convert(string source, ResolutionContext context)
    {
        if (!string.IsNullOrEmpty(source))
        {
            if (Enum.TryParse(source, out T result))
            {
                return result;
            }
        }

        return default;
    }
}

【问题讨论】:

  • 您总是可以通过为内部对象创建映射来避免ForPath
  • @LucianBargaoanu 但这是不可能的,因为它不是 2 个单独的对象
  • 真的吗? :) 那么Parent是什么?
  • @LucianBargaoanu 我们可以映射两个父级,但是我们只需要来自父级的 1 个属性而不是完整的父级,因此我们选择使用 ForPath,否则我们的模型需要很多。所以在模型中它不是一个单独的对象,只有 1 个属性
  • ForPath 不支持转换器(除非您想自己实现)。所以你要么改用MapFrom,要么放弃ForPath

标签: c# asp.net-core automapper


【解决方案1】:

感谢 Lucian Bargaoanu,我想出了这个解决方案。我将 valueConverter 重写为一个静态类,并使用 MapFrom 进行转换。

 public static class StringEnumExtension
{
    public static TaskType ToTaskType(this string source)
    {
        return ToEnum<TaskType>(source);
    }

    public static TaskQuestionType ToTaskQuestionType(this string source)
    {
        return ToEnum<TaskQuestionType>(source);
    }

    private static T ToEnum<T>(string source) where T : struct
    {
        if (!string.IsNullOrEmpty(source))
        {
            if (Enum.TryParse(source, out T result))
            {
                return result;
            }
        }

        return default;
    }
}

我像这样更新了映射:

CreateMap<TaskDto, TaskModel>()
            .ForPath(dest => dest.TaskType, opt => opt.MapFrom(src => src.TaskDefinition.TaskType.ToString()))
            .ReverseMap()
            .ForPath(dest => dest.TaskDefinition.TaskType, opt => opt.MapFrom(src => src.TaskType.ToTaskType()));

【讨论】:

    【解决方案2】:

    比起使用ForPath,我更喜欢同一配置文件中的其他地图。这样我仍然可以使用我的自定义值解析器:

    public class DstObject
    {
        public int AnotherProperty { get; set; }
        public DstChildObject DstChildObject { get; set; }
    }
    
    public class DstChildObject
    {
        public string SomeProperty { get; set; }      
    }
    
    public class MyMappingProfile : Profile
    {
        public MyMappingProfile()
        {
            this.CreateMap<SourceType, DstObject>()
                .ForMember(dst => dst.AnotherProperty, opt => opt.MapFrom(src => src.AnotherProperty))
                .ForMember(dst => dst.DstChildObject, opt => opt.MapFrom(src => src))
                ;
    
            this.CreateMap<SourceType, DstChildObject>()
                .ForMember(dst => dst.SomeProperty, opt => opt.MapFrom(src => src.SomeProperty))
                ;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-12
      • 2013-06-18
      • 2021-10-28
      • 2015-12-13
      • 1970-01-01
      • 2017-10-02
      • 1970-01-01
      相关资源
      最近更新 更多