AutoMapper: How to map only matching property names and ignore all others?
Asked Answered
T

3

9

I am new to AutoMapper and using version 6.2.2. I am trying to map a view model to an entity (also using Entity Framework). I want to update only the properties that exist in both the viewmodel and the entity. The entity has other navigational properties and related objects that are not part of the source viewmodel. I am currently getting an error that I have unmapped properties on the destination entity. Both my viewmodel and entity have over 40 properties so I do not want to explicitly add each one to the map.

Here is my code:

Map:

public static void RegisterMaps()
{
    AutoMapper.Mapper.Initialize(config =>
    {
                    config.CreateMap<EditApplicationViewModel, Application>();

    });

}

I have also tried the following but get the same error:

config.CreateMap<EditApplicationViewModel, Application>(MemberList.source);

Controller:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(EditApplicationViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        Application application = _applicationService.GetById(viewModel.ApplicationId);

        application = Mapper.Map(viewModel, application);
    }
}

Error Message:

InnerException: HResult=-2146233088 Message= Unmapped members were found. Review the types and members below. Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters ========================================================== String -> User (Destination member list) System.String -> ..***.entities.User (Destination member list)

Unmapped properties: removed - a very long list of related objects and properties on the destination

   Source=AutoMapper
   StackTrace:
        at lambda_method(Closure , EditApplicationViewModel , Application , ResolutionContext )

UPDATE:

I have also tried the following map. I am not receiving any errors but none of the source properties are updated on the destination.

config.CreateMap<EditApplicationViewModel, Application>().ForAllOtherMembers(opts=>opts.Ignore());
Trencherman answered 4/5, 2018 at 14:19 Comment(6)
Possible duplicate of Automapper v5 Ignore unmapped propertiesJamieson
The accepted answer of that post does not solve my issue. Therefore, I do not believe this to be a duplicate post. The case is different and the version of AutoMapper is also different.Trencherman
Have you tried IgnoreUnmapped extensions from https://mcmap.net/q/116193/-automapper-quot-ignore-the-rest-quot/…Jamieson
@Trencherman How is the case different? 6.2.2 > 5 and that answer is still valid.Gains
The referenced answer deals with ignoring all "unmapped" properties (i.e. If the mapping is not explicitly declared in the CreateMap, then ignore it, even if the property names match in both source and target. This is not what I am attempting to do.Trencherman
@Trencherman - "None of the source properties are being updated on the destination" = "nothing is being copied"Caddell
T
11

I was able to solve my problem and it had nothing to do with ignoring properties that didn't match by name between source and destination. It appears that the default behavior of AutoMapper already ignores these properties by default.

The error message was very deceiving:

  InnerException: 
       HResult=-2146233088
       Message=
Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters
==========================================================
String -> User (Destination member list)
System.String -> ***.***.***.entities.User (Destination member list)

The actual cause of my problem was a type mismatch. I have a string property in the view model called CreatedByUser. I also had a navigational property on my entity called CreatedByUser of type User.

I had to explicitly ignore this property in the CreateMap.

 config.CreateMap<EditApplicationViewModel, Application>()
                    .ForMember(d => d.CreatedByUser, opt => opt.Ignore());

No other directives were required to ignore any other properties that didn't exist on either source or destination.

Again, the error message I received "Unmapped members were found." through me off. The actual problem was a type mismatch.

Trencherman answered 7/5, 2018 at 16:53 Comment(3)
Sounds like a bug. Bad exception message.Spermogonium
damn right you are. In my case: source property was Nullabe boolean type, and destination - boolean only.Schaaf
And same issue for me although a variation on a theme: I had one object with public string Id {get;set;}If
H
0

You can use IgnoreUnMapped() function.

          config.CreateMap<EditApplicationViewModel, Application>().IgnoreUnMapped();
Haddad answered 4/5, 2018 at 14:57 Comment(3)
The .IgnoreUpmapped() method is not part of 6.2.2. My understanding is that config.CreateMap<EditApplicationViewModel, Application>().ForAllOtherMembers(opts=>opts.Ignore()) serves the same purpose. When I use that map, I do not get any errors but none of the properties are updated from source to destination.Trencherman
extension method doesn't exist in 6.2.2 version of AutomapperSchaaf
so what do we do here? i'm trying to map for a PUT and i don't have every prop and it seems strange to have to declare them manually.Unexpressed
C
0

Probably all your properties in both models don't have same names. For different name properties you can use following example:

var source = new Source();

void ConfigureMap(IMappingOperationOptions<Source, Dest> opt) {
    opt.ConfigureMap()
       .ForMember(dest => dest.Value, m => m.MapFrom(src => src.Value))
};

var dest = Mapper.Map<Source, Dest>(source, ConfigureMap);

Where for each new property name mismatch you define new .ForMember...

Carbonyl answered 4/5, 2018 at 14:57 Comment(3)
Per my question, I only want to update the properties that have the same names in both source and destination. I want to ignore all others. I am not looking to do property translations.Trencherman
Have you tried with extension like IgnoreAllNonExisting github.com/AutoMapper/AutoMapper/issues/1386Carbonyl
The extension method mentioned in the referenced GitHub link hasn't worked since version 5.0 because expression.TypeMap is no longer available. I am currently using the latest version (6.2.2). The link gave no workable alternatives.Trencherman

© 2022 - 2024 — McMap. All rights reserved.