仅当destination属性不为null时才使用UseDestinationValue

时间:2012-09-04 11:52:11

标签: c# .net automapper

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

类似的东西:

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属性为NOT NULL。现在我希望AutoMapper 使用Details属性的目标实例,因为它不是null。

    逻辑看起来像这样:

    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属性将为null(因为在这种情况下使用UseDestinationValue null)。

    < / LI>

    原因

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

    谢谢, 克里斯

3 个答案:

答案 0 :(得分: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);
            }
        };

答案 1 :(得分:0)

我认为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))

答案 2 :(得分:0)

我遇到了与NHibernate实体相同的问题,我找到了非常简单的解决方案。

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