【问题标题】:Using AutoMapper to merge objects使用 AutoMapper 合并对象
【发布时间】:2015-10-08 14:30:48
【问题描述】:

我正在尝试使用 AutoMapper 合并来自多个对象的数据,但遇到了一些我似乎无法解决的问题。

我有一个类似的对象:

public class Parent
{
    public string Id { get; set; }
    public List<Child> Children { get; set; }
}
public class Child
{
    public string Key { get; set; }
    public int? Value1 { get; set; }
    public int? Value2 { get; set; }
    public int? Value3 { get; set; }
    public int? Value4 { get; set; }
    public int? Value5 { get; set; }
}

显然子属性并不都是整数,但它们中的大多数都是可以为空的。

我的应用程序的两个不同层中有这些对象,因此我使用 AutoMapper 在它们之间进行转换:

{
    Mapper.CreateMap<Parent, ParentDTO>();
    Mapper.CreateMap<ParentDTO, Parent>();

    Mapper.CreateMap<Child, ChildDTO>();
    Mapper.CreateMap<ChildDTO, Child>();
}

转换效果很好,我对它的效果很满意。但是,现在我需要合并多个相同类型的对象。我将拥有一个对象的一个​​副本,其中填充了大部分或所有属性,另一个副本只有少数属性,其余为空。我希望将第二个(部分)对象的任何非空属性映射到第一个(已填写的)对象中的相应字段。正如this answer 的公认答案所说,我应该也可以使用 AutoMapper 来执行此操作,但它没有给出任何明确的示例。

但是,当我去执行操作时,我得到一个与其中任何一个对象相同的对象,而不是像我想要的那样组合。

{
    var bigParent = new Parent
    {
        Id = "14",
        Children = new List<Child>
        {
            new Child
            {
                Key = "A",
                Value1 = 10,
                Value2 = 20,
                Value3 = 30,
                Value4 = 40,
                Value5 = 50
            }                   
        }
    };

    var merge = new Parent
    {
        Id = "14",
        Children = new List<Child>
        {
            new Child
            {
                Key = "A",
                Value1 = null,
                Value2 = null,
                Value3 = 100,
                Value4 = null,
                Value5 = null
            }
        }
    };

    var res = Mapper.Map(merge, bigParent);
}

我期望 Child 的值是 10、20、100、40 和 50。但是,根据我是否将合并作为 Mapper.Map 中的源或目标,我会得到 null、null、100、null、null 或10、20、30、40、50。

有没有办法获得我的预期值?我认为列表是导致问题的原因,因为它不知道如何排列实体(以确定它们是否相同)。如果回答任何问题,我将能够通过查看一个或多个属性是否相同(在本例中为 Key)来确定子记录是否相同。

【问题讨论】:

标签: c# automapper-4


【解决方案1】:

如果您想忽略 AutoMapper Profile 中定义的映射中的空值,请使用:

public class MappingProfile : AutoMapper.Profile
{
  public MappingProfile()
  {
     this.CreateMap<Parent, Parent>()
         .ForAllMembers(o => o.Condition((source, destination, member) => member != null));
  }
}

【讨论】:

    【解决方案2】:

    Automapper 能够做到这一点,您的映射器需要这样配置:

    Mapper.Initialize(cfg =>
    {
        // necessary if you are mapping parent to a parent
        cfg.CreateMap<Parent, Parent>()
            .ForAllMembers(options =>
            {
                options.Condition(src => src.DestinationValue == null);
            });
        // necessary if you are mapping your child to a child
        cfg.CreateMap<Child, Child>()
            .ForAllMembers(options =>
            {
                options.Condition(src => src.DestinationValue == null);
            });
    });
    

    然后你的用法是这样的:

    var bigParent = new Parent
    {
        Id = "14",
        Children = new List<Child>
        {
            new Child
            {
                Key = "A",
                Value1 = 10,
                Value2 = 20,
                Value3 = 30,
                Value4 = 40,
                Value5 = 50
            }
        }
    };
    
    var merge = new Parent
    {
        Id = "14",
        Children = new List<Child>
        {
            new Child
            {
                Key = "A",
                Value1 = null,
                Value2 = null,
                Value3 = 100,
                Value4 = null,
                Value5 = null
            }
        }
    };
    
    var bigChild = new Child
    {
        Key = "A",
        Value1 = 10,
        Value2 = 20,
        Value3 = 30,
        Value4 = 40,
        Value5 = 50
    };
    
    var mergeChild = new Child
    {
        Key = "A",
        Value1 = null,
        Value2 = null,
        Value3 = 100,
        Value4 = null,
        Value5 = null
    };
    
    Mapper.Map(bigChild, mergeChild);
    Debug.Assert(mergeChild.Value3 == 100);
    
    Mapper.Map(bigParent, merge);
    Debug.Assert(merge.Children[0].Value3 == 100);
    

    【讨论】:

    • 我的代码没有 src.DestinationValue。我们正在使用个人资料。
    • 你是什么版本的?
    • 5.1.1;我能够以另一种方式解决我的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 2011-08-08
    相关资源
    最近更新 更多