UseDestinationValue only when the destination property is not null

How to configure AutoMapper mapping when I want to use the behavior from the UseDestinationValue method, but only when the destination property is NOT null .

Something like that:

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

EDIT

 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; } } 

Now an example of use. I have an ItemViewModel class and I want to map it to the Item class.

Display Configuration:

  Mapper.CreateMap<Item, ItemViewModel>() .ForMember(x => x.Details, _ => _.UseDestinationValue()) 
  • The property of the first property is the destination property. Item.Details not NULL. Now I want AutoMapper to use this target instance of the Details property because it is not null.

    And the logic looks like this:

     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); 

    Due to the presence of UseDestinationValue will leave an instance of Item.Details and set only the item.Details.Info property.

  • The property of the second property is the destination Item.Details property is NULL. Now I want AutoMapper not to use this null instance, but to create a new one. The question is how to set up the mapping to take this case into account?

    The logic looks like this:

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

    PROBLEM

    I have a problem here, because after matching, the Item.Details property will be null (due to using UseDestinationValue , which in this case is null ).

CAUSE

NHibernate, after receiving the object from the database, puts it in the proxy. Thus, the Details property of the loaded object is not of the type: ItemDetails , but ItemDetailsNHibernateProxy - so I have to use this type when I want to subsequently save this existing object in the database. But if this property is null , then I cannot use the null address value, so Automapper must create a new instance.

Thank you, Chris

+6
source share
3 answers

There was the same problem, but with EF. Cryss's comment on using BeforeMap pointed me in the right direction.

I ended up with a code similar to:

In the Configure () method:

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

Then action:

 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
source

I think the NullSubstitute option will work for you. See: http://weblogs.asp.net/psteele/archive/2011/03/18/automapper-handling-null-members.aspx

EDIT

It looks like you might need to add some conditional logic for your mapping for Details (and skip the UseDestinationValue parameter):

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

I had the same problem with NHibernate objects and I found a pretty simple solution.

You must initialize the Details property in the ItemViewModel constructor. So the destination value is not null. Of course, this does not work in more complex cases (for example, abstract classes).

0
source

Source: https://habr.com/ru/post/924532/


All Articles