【问题标题】:Automapper map one property to multipleAutomapper 将一个属性映射到多个
【发布时间】:2015-01-11 02:14:45
【问题描述】:

我在源对象和目标对象之间面临 AutoMapper 的挑战。 我将尝试解释这种情况。 在我的 src 对象上,我有一个字符串,根据它的长度,它应该映射到我的目标对象的多个属性。

class source
{
   public int Id {get; set;}
   /* some other properties */
   public string Value {get; set;}
}

class destination
{
   public int Id {get; set;}
   /* some other properties with the same name as the source */
   public string Value1 {get; set;}
   public string Value2 {get; set;}
   public string Value3 {get; set;}
}

预期的最大长度为 30 个字符(它可以小于仅映射到两个或一个属性的长度)。因此,每 10 个将映射到每个目标属性。我试图使用 AutoMapper 中的 ResolveUsing 方法,但无法让函数知道我应该带回哪个段。 所以我想忽略这个属性的映射,并在 Automapper 完成其他属性的工作后手动执行此操作

【问题讨论】:

    标签: c# visual-studio-2010 automapper automapper-2 automapper-3


    【解决方案1】:

    您可以使用 ForMember 规范创建映射函数

    private void CreateMap(){
        Mapper.CreateMap<source,destination>()
            .ForMember(v=> v.Value1,
                opts => opts.MapFrom( src=> src.Value.Substring(0,10)))
            .ForMember(v=> v.Value2,
                opts => opts.MapFrom( src=> src.Value.Substring(10,10)))
            .ForMember(v=> v.Value3,
                opts => opts.MapFrom( src=> src.Value.Substring(20,10)));
    }
    

    您可以只评估原始字符串包含适当长度的每个映射,否则返回 string.Empty 或填充它以满足您的需求。

    用法(使用 LinqPad):

    void Main(){
       CreateMap();
       var source = new source();
       source.Id=1;
       source.Value="123454678901234546789012345467";
       var res = Mapper.Map<destination>(source);
       res.Dump();
    }
    

    【讨论】:

    • 这几乎可以工作——问题是你必须对每个MapFrom 调用进行两次长度检查——一个用于字符串的开始和结束索引以确保@987654324 @ 调用不会失败。
    • 如此真实!我会支持你的,但我还没有足够的代表=P
    • @soulus 实际上我更喜欢您的解决方案,因为当您映射到现有实例时它也可以工作(即,当您使用 EF 从数据库加载实体时,对象创建和映射必须是两个单独的操作)
    【解决方案2】:

    您可以这样做的方法是使用.ConstructUsing 告诉 AutoMapper 如何创建对象您可以创建一个函数来手动映射 Value1Value2Value3,然后让 AutoMapper 映射其余属性.例如:

    static destination ConstructDestination(source src)
    {
        List<string> chunked = src.Value
            .Select((ch, index) => new { Character = ch, Index = index })
            .GroupBy(
                grp => grp.Index / 10,
                (key, grp) => new string(grp.Select(itm => itm.Character).ToArray()))
            .ToList();
    
        var dest = new destination
        {
            Value1 = chunked.Count > 0 ? chunked[0] : null,
            Value2 = chunked.Count > 1 ? chunked[1] : null,
            Value3 = chunked.Count > 2 ? chunked[2] : null
        };
    
        return dest;
    }
    
    Mapper.CreateMap<source, destination>()
        .ConstructUsing(ConstructDestination)
        .ForMember(dest => dest.Value1, opt => opt.Ignore())
        .ForMember(dest => dest.Value2, opt => opt.Ignore())
        .ForMember(dest => dest.Value3, opt => opt.Ignore());
        /* Id is mapped automatically. */
    

    当然,如果在您的实际场景中,您有超过三个 Value 字段,这可能会变得很糟糕——在这种情况下,您可以使用反射来设置属性。

    【讨论】:

    • 感谢您的回复。我不知道如何使用 ConstructUsing 现在很清楚了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-29
    • 1970-01-01
    • 1970-01-01
    • 2014-03-31
    • 1970-01-01
    • 2011-06-26
    相关资源
    最近更新 更多