Automapper Convert from Multiple Sources

AutoMapper convert from multiple sources

You cannot directly map many sources to single destination - you should apply maps one by one, as described in Andrew Whitaker answer. So, you have to define all mappings:

Mapper.CreateMap<People, PeoplePhoneDto>();
Mapper.CreateMap<Phone, PeoplePhoneDto>()
.ForMember(d => d.PhoneNumber, a => a.MapFrom(s => s.Number));

Then create destination object by any of these mappings, and apply other mappings to created object. And this step can be simplified with very simple extension method:

public static TDestination Map<TSource, TDestination>(
this TDestination destination, TSource source)
{
return Mapper.Map(source, destination);
}

Usage is very simple:

var dto = Mapper.Map<PeoplePhoneDto>(people)
.Map(phone);

Automapper convert from multiple source when one of the source is null

public static TDestination Map<TSource, TDestination>(this TDestination destination, TSource source)
{
if(source == null)
return destination;

return Mapper.Map(source, destination);
}

Automapper multiple source to single target in v8.0

Here is a working demo like below:

Model:

public class People
{
public string FirstName { get; set; }
public string LastName { get; set; }
}

public class Phone
{
public string Number { get; set; }
}

public class PeoplePhoneDto
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string PhoneNumber { get; set; }
}

AutoMapper profile:

public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<People, PeoplePhoneDto>();
CreateMap<Phone, PeoplePhoneDto>()
.ForMember(d => d.PhoneNumber, a => a.MapFrom(s => s.Number));
}
}

Startup.cs:

services.AddAutoMapper(typeof(AutoMapperProfile));

Controller:

public class HomeController : Controller
{
private readonly IMapper _mapper;

public HomeController(IMapper mapper)
{
_mapper = mapper;
}
public IActionResult Index()
{
var people = new People() { FirstName = "aaa", LastName = "bbb" };
var phone = new Phone() { Number = "12345" };
var model = _mapper.Map<PeoplePhoneDto>(people); // map dto1 properties
_mapper.Map(phone, model);

//do your stuff...
return View();
}
}

Result:
Sample Image

Automapper multiple source to one destination

I have used following technique and it's works well.

public void IntializeUserCompanyRolesMapping()
{
CreateMap<Roles, RolesViewModel>();

CreateMap<ICollection<Roles >, CompanyViewModel>()
.ForMember(d => d.CompanyName , opt => opt.Ignore())
.ForMember(d => d.CompanyAddress , opt => opt.Ignore())
.ForMember(d => d.RolesViewModel, opt => opt.MapFrom(s => s));

CreateMap<UserRoles, CompanyViewModel>()
.ForMember(d => d.RolesViewModel , opt => opt.MapFrom(s => s.Roles ));

CreateMap<Person, Person>()
.ForMember(d => d.CompanyViewModel , opt => opt.MapFrom(s => MapCompanyToCompanyViewModel(s.Companies )));

}

I have used custom method to loop over the list of companies and added into the list of company view model.

    private Collection<CompanyViewModel> MapCompanyToCompanyViewModel(ICollection<Company> Companies )
{
var companyViewModels = new Collection<CompanyViewModel>();
foreach (var company in Companies)
{
foreach (var companyViewModel in company.UserRoles.Select(Mapper.Map<CompanyViewModel>))
{
companyViewModels.Add(companyViewModel);
}
}
return companyViewModels;

}

Automapper - Multi object source and one destination

Map has an overload that takes a source and destination object:

d = AutoMapper.Mapper.Map<sourceone, destination>(sourceone);

/* Pass the created destination to the second map call: */
AutoMapper.Mapper.Map<sourcetwo, destination>(sourcetwo, d);

Automapper: Custom mapping for multiple source arrays to a single destination array

On your automapper profile configuration add the following

CreateMap<CatDto, Cat>();
CreateMap<DogDto, Dog>();

On the custom mapper

public class AnimalConverter : ITypeConverter<ConfigDto, AnimalConfig>
{
public AnimalConfig Convert(ConfigDto source, AnimalConfig destination, ResolutionContext context)
{
List<IAnimal> destAnimals = new List<IAnimal>();

//add cats
destAnimals.AddRange(context.Mapper.Map<List<Cat>>(source.Cats));

//add dogs
destAnimals.AddRange(context.Mapper.Map<List<Dog>>(source.Dogs));

return new AnimalConfig(){Animals = destAnimals.ToArray()};
}
}

Merge multiple sources into a single destination

Here

cfg.CreateMap<ICollection<Volume>, PreferenceVM>()
.ForMember(x => x.Volumes, y => y.MapFrom(src => src)).ReverseMap();

and

cfg.CreateMap<ICollection<Service>, PreferenceVM>()
.ForMember(x => x.Services, y => y.MapFrom(src => src)).ReverseMap();

you create mappings from ICollection<TSource>.

However later on you are trying to map IQeryable<TSource>. While AutoMapper can use a base mapping to map a derived class, IQueryable<T> does not derive from ICollection<T>, hence the missing type map exception.

The solution is to create a mapping from some common base interface of IQueryable<T> and ICollection<T>, which is IEnumerable<T>.

So replace the above with:

cfg.CreateMap<IEnumerable<Volume>, PreferenceVM>()
.ForMember(x => x.Volumes, y => y.MapFrom(src => src));
cfg.CreateMap<IEnumerable<Service>, PreferenceVM>()
.ForMember(x => x.Services, y => y.MapFrom(src => src));

and the current issue will be solved.

Note that ReverseMap does not work in such scenarios, so I've just removed it. If you need such functionality, you have to create that mappings manually (eventually using ConvertUsing because there is no destination member).

AutoMapper problem with custom convert from source to destination

I managed to find my mistake, and I have to admit it is a silly one, but took me a lot of time to figure. The problem is in the line var ss = modelMapper.Map<ApiModel>(settings.Settings);
See I have the Profile like this:

CreateMap<DbModel, ApiModel>()
.ConstructUsing((source, context) =>
{
var res = JsonConvert.DeserializeObject<ApiModel>(source.Settings);
return new ApiModel
{
Colors = res.Colors
};
});

It expects the source to be a DbModel object, but in fact I pass a property of this object which is in fact a string. And I do not have defined that kind of mapping, that is why I get the error.

The right usage have to be: var ss = modelMapper.Map<ApiModel>(settings);

So thanks for all your suggestions!

Regards,
Julian



Related Topics



Leave a reply



Submit