C#使用automapper

时间:2018-03-28 14:24:46

标签: c# automapper

我的问题类似于this question,只是我需要合并更深层次。

我有两个相同类型的相似对象。我需要将这些合并为最终结果。一个对象填充来自更可靠源的数据,而另一个对象更完整。我的最终结果应包含来自更可靠来源的所有值。但是,如果可靠来源中没有值,则应从更完整的来源填写。

我的对象看起来像这样(简化):

public class Body {
    int Id
    Client Client
    Details Details
}

public class Client {
    int Id
    Name Name
    Address Address
}

public Name {
    string FirstName
    string LastName
    etc...
}

public class Address {
    string StreetName
    string HouseNumber
    etc...
}

public class Details {
    Details1 Details1
    Details2 Details2
    many more classes which contains more nested classes...
}

所以,我发现我可以使用AutoMapper Condition选项来指定只映射目标类中的空值。

Mapper.CreateMap<Body, Body>()
            .ForAllMembers(opt => opt.Condition(dest => dest.DestinationValue == null));
Mapper.Map(completeObject, reliableObject);

ForAllMembers仅适用于该类的直接子成员。因此,上述语句仅检查reliableObject中的Id,Client en Details字段是否为空。它不会检查架构中更深层次的值,例如reliableObject.Client.Address.StreetName

为实现这一目标,我必须为我的架构中的每个类配置Condition选项,这些选项很多,并分别映射它们。

有没有办法告诉AutoMapper将此条件应用于架构的每个级别? AutoMapper甚至是合并这些对象的最佳方式吗?

我使用AutoMapper版本3.2.1。

1 个答案:

答案 0 :(得分:1)

在较新版本的AutoMapper中,Profile.AddConditionalMapper()允许您定义全局约定,但在版本3中,这是不可能的。

然而,你可以做的是制作一个通用方法,例如:

public void MapIfDestinationIsNull<T>()
{
    Mapper.CreateMap<T, T>().ForAllMembers(opt => opt.Condition(dest => dest.DestinationValue == null));
}

并用所有类型调用它。同样多行代码,但每一行都更短。

或者,如果你有办法将所有类型都放入一个数组中(例如你有一个单独的程序集,或者它们有某种通用接口/基类),你可以使用反射来调用这个方法所有类型:

foreach (var type in types)
{
    GetType().GetMethod("MapIfDestinationIsNull").MakeGenericMethod(type).Invoke(this, new object[] { });
}

我可以给你的最好建议是简单地升级你的AutoMapper,但如果那不可能那么你就不得不采取一些反思。您还可以查看AutoMapper的源代码,看看新版本如何处理这些内容,并简单地模仿它。