【问题标题】:UseDestinationValue only when destination property is not null仅当目标属性不为空时才使用目标值
【发布时间】:2012-09-04 11:52:10
【问题描述】:

当我想使用 UseDestinationValue 方法中的行为时如何配置 AutoMapper 映射,但仅当目标属性不是 null 时。

类似的东西:

Mapper.CreateMap<Item, ItemViewModel>()
    .ForMember(x => x.Details, _ => _.UseDestinationValue(dontUseWhenNullDestination: true))

编辑

class ItemDetails {
    public string Info { get; set; }
    public string ImportantData { get; set; } // only in Domain, not in ViewModel
}

class Item {
    public ItemDetails Details { get; set; }
}

class ItemDetailsViewModel {
    public string Info { get; set; }
}

class ItemViewModel {
    public ItemDetailsViewModel Details { get; set; }
}

现在的用法示例。我有一个ItemViewModel 类,我想将它映射到Item 类。

映射配置:

    Mapper.CreateMap<Item, ItemViewModel>()
        .ForMember(x => x.Details, _ => _.UseDestinationValue())
  1. 第一种情况 - 目标属性Item.Details 属性不为空。现在我希望 AutoMapper 使用 Details 属性的这个目标实例,因为它不为空。

    逻辑如下:

    var item = new Item { 
        Details = new Details {
            Info = "Old text",
            ImportantData = "Data"
        }
    };
    
    var itemViewModel = new ItemViewModel { 
        Details = new DetailsViewModel {
            Info = "New text"
        }
    };       
    
    Mapper.Map(itemViewModel, item);
    

    由于存在UseDestinationValue,AutoMapper 将离开item.Details 实例并仅设置item.Details.Info 属性。

  2. 第二种情况 - 目标属性 Item.Details 属性为 NULL。现在我希望 AutoMapper 不使用这个空实例,而是创建一个新实例。问题是如何配置映射以考虑这种情况?

    逻辑如下:

    var item = new Item { 
        Details = null
    };
    
    var itemViewModel = new ItemViewModel { 
        Details = new DetailsViewModel {
            Info = "New text"
        }
    };
    
    Mapper.Map(itemViewModel, item);
    

    问题

    这里我有一个问题,因为映射后,item.Details 属性将为空(因为使用了UseDestinationValue,在这种情况下为null)。

原因

NHibernate 从数据库中获取实体后,将其放入代理中。所以加载对象的Details 属性不是一个类型:ItemDetails,而是ItemDetailsNHibernateProxy - 所以我必须使用这种类型,当我想稍后将这个现有对象保存到数据库时。但是如果这个属性是null,那么我不能使用空目标值,所以Automapper应该创建一个新实例。

谢谢, 克里斯

【问题讨论】:

  • 那么,如果 UseDestinationValue 为 null,您是否想做其他事情?
  • 是的,当目标属性为 NULL 时,我想做其他事情。
  • 您能否提供一些工作示例代码,向您展示您希望如何映射事物与 Auotmapper 当前所做的事情。我只是不明白你在问什么。
  • 我希望 automapper 使用复杂属性 Details 的 destination instance(不是创建新属性),然后设置 ItemDetails 类的内部属性。但这应该只在Details属性不为null时才有效(因为我想使用这个实例),所以当Details属性为null时,不要使用这个null值,而是创建一个新实例。
  • 很遗憾没有。现在我正在做的是在 BeforeMap 操作中检查目标属性值是否为空。

标签: c# .net automapper


【解决方案1】:

遇到同样的问题,但使用 EF。 Cryss 关于使用 BeforeMap 的评论为我指明了正确的方向。

我最终得到的代码类似于:

在 Configure() 方法中:

Mapper.CreateMap<ItemViewModel, Item>()
           .AfterMap((s, d) => { MapDetailsAction(s, d); })
           .ForMember(dest => dest.Details, opt => opt.UseDestinationValue());

然后是动作:

Action<ItemViewModel, Item> MapDetailsAction = (source, destination) =>
        {
            if (destination.Details == null)
            {
                destination.Details = new Details();
                destination.Details =
                    Mapper.Map<ItemViewModel, Item>(
                    source.Details, destination.Details);
            }
        };

【讨论】:

    【解决方案2】:

    我认为NullSubstitute 选项对您有用。见:http://weblogs.asp.net/psteele/archive/2011/03/18/automapper-handling-null-members.aspx

    编辑

    看起来您可能需要为详细信息的映射添加一些条件逻辑(并跳过UseDestinationValue 选项):

    .ForMember(d => d.Details, 
        o => o.MapFrom(s => s.Details == null ? new ItemDetails() : Mapper.Map<ItemDetailsViewModel, ItemDetails>(s.Details))
    

    【讨论】:

    • NullSubstitute 在源值为 null 时很有用。
    【解决方案3】:

    我在处理 NHibernate 实体时遇到了同样的问题,我找到了非常简单的解决方案。

    您应该在 ItemViewModel 构造函数中初始化 Details 属性。这样,目标值永远不会为空。当然,这不适用于更复杂的情况(如抽象类)。

    【讨论】:

      猜你喜欢
      • 2012-03-10
      • 2016-02-29
      • 2017-09-16
      • 1970-01-01
      • 2019-12-25
      • 1970-01-01
      • 1970-01-01
      • 2016-08-29
      • 2021-02-21
      相关资源
      最近更新 更多