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:
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
Visual Studio Debugging "Quick Watch" Tool and Lambda Expressions
How to Convert Datatable to JSON String Using JSON.Net
Convert Array of Bytes to Bitmapimage
What Is the Best Scripting Language to Embed in a C# Desktop Application
Filter/Search Using Multiple Fields - ASP.NET MVC
How to Retrieve Data from a SQL Server Database in C#
Ef 4.1 - Code First - JSON Circular Reference Serialization Error
How to Reconcile Idisposable and Ioc
How to Call Generic Method with a Given Type Object
Hashtable with Multidimensional Key in C#
Icecast 2: Protocol Description, Streaming to It Using C#
How to Split a String by Strings and Include the Delimiters Using .Net
Why Was "Switchto" Removed from Async Ctp/Release
How to Easily Initialize a List of Tuples
How to Get Values from Igrouping
Using Process.Start() to Start a Process as a Different User from Within a Windows Service
Use Xml Includes or Config References in App.Config to Include Other Config Files' Settings