I am trying to map IEnumerable to List. I am not sure how to get it work. Here is what I have tried so far.
I am getting an error "Custom configuration for members is only supported for top-level individual members on a type."
Source: IEnumerable<Source>
Target: List<Target>
AutoMapper.Mapper.Map(sourceIEnum, TargetList);
Mapper.CreateMap<IEnumerable<Source>, List<Target>>()
.ForMember(f => f, mp => mp.MapFrom(
mfrom => mfrom.Select(s => AutoMapper.Mapper.Map(s, new Target())
).ToList())
);
Mapper.CreateMap<Source, Target>()
.ForMember(f => f.TargetPropertyA, mp => mp.MapFrom(mfrom => mfrom.FromA.Value))
.ForMember(f => f.TargetPropertyB, mp => mp.MapFrom(mfrom => mfrom.FromB.Value))
.ForMember(f => f.TargetPropertyC, mp => mp.MapFrom(mfrom => mfrom.FromC.Value))
.ForMember(f => f.InnerObjectTarget, mp => mp.MapFrom(
mfrom => mfrom.Select(s => AutoMapper.Mapper.Map(s, new InnerObjectTarget())
).ToList())
);
Mapper.CreateMap<SourceInner, TargetInner>()
.ForMember(f => f.TargetInnerPropA, m => m.MapFrom(source => source.InnerA))
.ForMember(f => f.TargetInnerPropB, m => m.MapFrom(source => source.InnerB))
.ForMember(f => f.TargetInnerPropC, m => m.MapFrom(source => source.InnerC));
There a several ways to map an IEnumerable<Source>
to an IEnumerable<Target>
. I'll show the three most convenient ones.
Taking the AdventureWorks database (2008R2) as an example, I defined three DTO classes:
class ProductModelDto
{
public string Name { get; set; }
public IEnumerable<ProductDto> Products { get; set; }
}
class ProductDto
{
public string Name { get; set; }
public string Number { get; set; }
public IEnumerable<ProductReviewDto> ProductReviews { get; set; }
}
class ProductReviewDto
{
public string ReviewerName { get; set; }
public string Email { get; set; }
}
Here's the only mapping I defined:
Mapper.CreateMap<ProductModel, ProductModelDto>();
Mapper.CreateMap<Product, ProductDto>()
.ForMember(dto => dto.Number, m => m.MapFrom(p => p.ProductNumber));
Mapper.CreateMap<ProductReview, ProductReviewDto>()
.ForMember(dto => dto.Email, m => m.MapFrom(pr => pr.EmailAddress));
Just a query:
// A ProductModel having a Product with ProductReviews
var query = db.ProductModels.Where(pm => pm.ProductModelID == 64);
Now the most convenient ways, in my opinion, to map the source ProductModel
s to IEnumerable<ProductModelDto>
are these three:
1. query.Select(Mapper.Map<ProductModelDto>)
2. Mapper.Map<List<ProductModelDto>>(query)
3. query.ProjectTo<ProductModelDto>() (Project().To<> prior to v. 4.1.0)
And if you do ToList()
, you've mapped IEnumerable
to List
.
The output is the same for all three alternatives:
- HL Mountain Pedal
- HL Mountain Pedal; PD-M562
- David; [email protected]
- Jill; [email protected]
As you see, AutoMapper doesn't need explicit mapping definitions for the IEnumerable
s. Not for the top level and not for the nested collections. It also maps a nested collection when the names are identical in the source and target classes and a mapping is defined for the elements in the collection.
Case 3 is a special case. It projects the IQueryable
to the target, which is still an IQueryable
. Predicates applied after the mapping are still translated to SQL and the query tries to select only the fields from the database that are necessary for projection. The latter doesn't always succeed when DTOs are nested though, as in this case. Linq-to SQL appeared to execute two queries with option 3 (but three for 1 and 2).
As long as Source to Target mapping is defined, you don't need to define IEnumerable<Source>
to List<Target>
mapping explicitly.
Automapper is smart enough to map the basic collections automatically (List, IEnumerable, Collection etc.) if the collection element types are mapped. so remove all code between collection mapping and try again.
This snippet..
Mapper.CreateMap<IEnumerable<Source>, List<Target>>()
.ForMember(f => f, mp => mp.MapFrom(
mfrom => mfrom.Select(s => AutoMapper.Mapper.Map(s, new Target())
).ToList())
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With