简体   繁体   中英

Unflatten by convention with automapper

In my project I'm trying to use automapper to unflatten my command objects to my domain objects by convention as much as possible.
It works when I explicitly map the two members in the mapping profile, but according to the automapper documentation I think this should also work by convention. I created a dotnetfiddle to demonstrate the minimal case.

Related questions end up with people explicitly adding the mapping, but that kind of goes against what Automapper is built for and contradicts the documentation, no? It doesn't work with flattening either, so the reversemap is a red herring I think.

The mapping

public class Mapping: Profile
{
    public Mapping()
    {
        this.CreateMap<CreateSelectionCommand, Selection>();
        // .ForMember(selection => selection.Name, opt => opt.MapFrom(x => x.SelectionName))
        .reverseMap()
    }
}

What I expect to work

[Fact]
public void ShouldMapName()
{
    var cmd = new CreateSelectionCommand {SelectionName = "selectionName"};
    var selection = _mapper.Map<Selection>(cmd);

    Assert.Equal(cmd.SelectionName, selection.Name); <== selection.Name == ""
}

Classes for context

public class Selection
{
    public string Name { get; set; }
}

public class CreateSelectionCommand
{
    public string SelectionName { get; set; }
}

Did I misread the docs or am I missing something?

Flattening is about mapping nested "complex" objects to properties on "higher" level ie in your case if CreateSelectionCommand had property Selection of type which had Name property it would be mapped to SelectionName in destination type (see this fiddle ).

You can try to use prefixes by adding:

cfg.RecognizePrefixes("Selection");

to your configuration (see this fiddle ) but I doubt that it is suitable option for convention based handling.

Also it seems that you can add custom name convention using ISourceToDestinationNameMapper and AddMemberConfiguration :

class TypeNamePrefixedSourceToDestinationNameMapper : ISourceToDestinationNameMapper
{
    public MemberInfo GetMatchingMemberInfo(IGetTypeInfoMembers getTypeInfoMembers, TypeDetails typeInfo,
        Type destType,
        Type destMemberType, string nameToSearch)
    {
        return getTypeInfoMembers.GetMemberInfos(typeInfo)
            .FirstOrDefault(mi => mi.Name == destType.Name + nameToSearch);
    }
}

var config = new MapperConfiguration(cfg =>
{
    cfg.AddMemberConfiguration().AddName<TypeNamePrefixedSourceToDestinationNameMapper>();

    // ...
}

At least it works in this simple case, see this fiddle .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM