1

I have a list of DTOs and want to map this list to a list of entites. The entity itself has one property which comes from another source. Can I map this property to all items of the list with one map.

My classes:

Entity:

public class Account
{
   public int Id {get;set;}
   public string Name {get;set;}
   public Guid ExternalId {get;set;}
}

DTO:

public class ExternalAccountDto
{
   public int Id {get;set;}
   public string Name {get;set;}
}

My Service:

public class AccountService
{
   public async Task AddExternalAccounts(Guid externalId, List<ExternalAccountDto> accounts)
   {            
        var entities = _mapper.Map(accounts);
        // TODO: Map 'externalId' to all entities
        // _mapper.Map(externalId, entities); // DOES NOT WORK!

        _context.Create(entities);
   }

}

Mapping

public class AccountProfile: Profile
{
   public AccountProfile()
   {
      CreateMap<ExternalAccountDto, Account>();

      // TODO: CreateMap for Guid on every Account
   }
}

Can anyone give me some advice!

2
  • As a first thought, I would say this is probably wrong and why not just use Linq after the map, but if you are adament to do this through auto mapper I think the only possible way would be to use a ValueTransformer and pass in a Func to set the value. Let me know if you want some help with that Commented Aug 30, 2019 at 8:19
  • docs.automapper.org/en/latest/… Commented Aug 30, 2019 at 8:27

1 Answer 1

5

You should use the AfterMap function to do some postprocessing on the mapped items.

There are two ways to go about this. One is using something statically defined in the mapping profile. But in your case, you have something that's dynamic at runtime, like the ExternalId. Doing the aftermap in your AccountService then makes perfect sense.

I've found these kind of constructions very useful, especially when I want to consult other injected services for additional information.

   public void AddExternalAccounts(Guid externalId, List<ExternalAccountDto> accounts)
    {
        var entities = _mapper.Map<List<ExternalAccountDto>, List<Account>>(accounts, 
            options => options.AfterMap((source, destination) =>
                {
                    destination.ForEach(account => account.ExternalId = externalId);
                }));
    }

Two more cents regarding the AccountProfile class:
You can check upon creation of the mapping profile if the mapping profile is correct. This will save you a headache running into this problem later at runtime. You'll know immediately that there is a problem with the configuration.

 var config = new MapperConfiguration(cfg =>
        {
            cfg.AddProfile<MappingProfile>();
            cfg.AllowNullDestinationValues = false;
        });

        // Check that there are no issues with this configuration, which we'll encounter eventually at runtime.
        config.AssertConfigurationIsValid();

        _mapper = config.CreateMapper();

This also notified me that an .Ignore() on the ExternalId member of the Account class was required:

 CreateMap<ExternalAccountDto, Account>().ForMember(d => d.ExternalId, a => a.Ignore());
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.