我正在尝试将IEnumerable映射到List。我不确定如何让它工作。这是我到目前为止尝试过的。
我收到错误"成员的自定义配置仅支持类型的顶级单个成员"。
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));
有几种方法可以将IEnumerable<Source>
映射到IEnumerable<Target>
。我将展示三个最方便的。
以 AdventureWorks 数据库 (2008R2) 为例,我定义了三个 DTO 类:
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; }
}
这是我定义的唯一映射:
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));
只是一个查询:
// A ProductModel having a Product with ProductReviews
var query = db.ProductModels.Where(pm => pm.ProductModelID == 64);
现在,在我看来,将源ProductModel
映射到IEnumerable<ProductModelDto>
的最方便方法是以下三种:
1. query.Select(Mapper.Map<ProductModelDto>)
2. Mapper.Map<List<ProductModelDto>>(query)
3. query.ProjectTo<ProductModelDto>() (Project().To<> prior to v. 4.1.0)
如果你这样做ToList()
,你就IEnumerable
映射到List
。
所有三种备选方案的输出都相同:
- HL Mountain Pedal
- HL Mountain Pedal; PD-M562
- David; david@graphicdesigninstitute.com
- Jill; jill@margiestravel.com
如您所见,AutoMapper 不需要显式映射定义IEnumerable
。不适用于顶层,也不适用于嵌套集合。当源类和目标类中的名称相同,并且为集合中的元素定义映射时,它还映射嵌套集合。
案例 3 是一个特例。它将IQueryable
投影到目标,这仍然是一个IQueryable
。映射后应用的谓词仍会转换为 SQL,并且查询仅尝试从数据库中选择投影所需的字段。但是,当 DTO 嵌套时,后者并不总是成功,就像在这种情况下一样。Linq-to SQL 似乎使用选项 3 执行了两个查询(但对选项 1 和 2 执行了三个查询)。
只要定义了源到目标映射,就不需要显式定义IEnumerable<Source>
到List<Target>
映射。
如果映射了集合元素类型,Automapper 足够智能,可以自动映射基本集合(List、IEnumerable、Collection 等)。 因此,请删除集合映射之间的所有代码,然后重试。
这个片段..
Mapper.CreateMap<IEnumerable<Source>, List<Target>>()
.ForMember(f => f, mp => mp.MapFrom(
mfrom => mfrom.Select(s => AutoMapper.Mapper.Map(s, new Target())
).ToList())
);