You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Clean架构下PagedList分页后AutoMapper类型映射报错求助

AutoMapper映射PagedList类型错误的解决方法

问题背景

基于Clean架构开发项目,此前返回IEnumerable<T>类型时AutoMapper映射完全正常,但实现包含分页数据的PagedList<T>并添加分页头后,出现AutoMapper类型映射错误。

项目相关代码

1. 基础设施层泛型Repository

public IQueryable<T> Get()
{
    return _context.Set<T>().AsNoTracking();
}

public async Task<PagedList<T>> GetAsync(PagingParameters parameters, Expression<Func<T, object>> orderByExpression)
{
    var query = Get();

    if (orderByExpression != null)
    {
        query = query.OrderBy(orderByExpression);
    }

    var count = await query.CountAsync();
    var items = await query
                .Skip((parameters.PageNumber - 1) * parameters.PageSize)
                .Take(parameters.PageSize).ToListAsync();

    return new PagedList<T>(items, count, parameters.PageNumber, parameters.PageSize);
}

CategoryRepository继承该泛型Repository,无自定义方法。

2. 应用层CategoryService代码

public async Task<PagedList<CategoryDTO>> GetCategories(PagingParameters parameters)
{
    Expression<Func<Category, Object>> orderByExpression;
    switch (parameters.OrderedBy.ToLower())
    {
        case "name":
            orderByExpression = x => x.Nome;
            break;
        default:
            orderByExpression = x => x.Id;
            break;
    }

    var categoriesEntity = await _categoryRepository.GetAsync(parameters, orderByExpression);
    
    // 报错发生在此处:
    return _mapper.Map<PagedList<CategoryDTO>>(categoriesEntity);
}

3. CategoriesController的Get方法

[HttpGet]
public async Task<ActionResult<PagedList<CategoriaDTO>>> Get([FromQuery] PagingParameters parameters)
{
    var categorias = await _categoriaService.GetCategorias(parameters);

    // 分页头
    var metadata = new
    {
        categorias.TotalCount,
        categorias.PageSize,
        categorias.CurrentPage,
        categorias.TotalPages,
        categorias.HasNext,
        categorias.HasPrevious
    };

    Response.Headers.Add("X-Pagination", JsonSerializer.Serialize(metadata));

    return Ok(categorias);
}

4. PagedList定义

namespace Store.Domain.Pagination
{
    public class PagedList<T> : List<T>
    {
        public int CurrentPage { get; set; }
        public int TotalPages { get; set; }
        public int PageSize { get; set; }
        public int TotalCount { get; set; }

        public bool HasPrevious => CurrentPage > 1;
        public bool HasNext => CurrentPage < TotalPages;

        public PagedList(List<T> items, int count, int pageNumber, int pageSize)
        {
            TotalCount = count;
            PageSize = pageSize;
            CurrentPage = pageNumber;
            TotalPages = (int)Math.Ceiling(count / (double)pageSize);

            AddRange(items);
        }
    }
}

已尝试的配置与错误信息

已配置基础映射:

CreateMap<Category, CategoryDTO>().ReverseMap();

尝试过的PagedList映射配置:

  • CreateMap(typeof(PagedList<Category>), typeof(PagedList<CategoryDTO>));
  • 错误写法:CreateMap<typeof(PagedList<Category>), typeof(PagedList<CategoryDTO>)>();

均触发错误:

"Incorrect number of arguments supplied for call to method 'Store.Application.DTOs.CategoryDTO get_Item(Int32)' (Parameter 'property')"

尝试创建PagedListDTO<T>并配置CreateMap(typeof(PagedList<Category>), typeof(PagedListDTO<CategoryDTO>));,提示PagedList需要无参构造函数,添加后错误仍存在。

可行解决方案

方案1:手动构造目标PagedList对象

绕过AutoMapper对整个PagedList的映射,手动将实体列表映射为DTO列表,再传入PagedList构造函数:

public async Task<PagedList<CategoryDTO>> GetCategories(PagingParameters parameters)
{
    // ... 原有逻辑获取categoriesEntity ...
    
    var categoryDtos = _mapper.Map<List<CategoryDTO>>(categoriesEntity);
    return new PagedList<CategoryDTO>(categoryDtos, categoriesEntity.TotalCount, categoriesEntity.CurrentPage, categoriesEntity.PageSize);
}

这个方法简单直接,不需要额外配置AutoMapper,避免复杂的泛型映射问题。

方案2:为AutoMapper配置自定义类型转换器

创建针对PagedList<TSource>到PagedList<TDestination>的自定义转换器,让AutoMapper知道如何处理这种泛型类型的映射:

public class PagedListConverter<TSource, TDestination> : ITypeConverter<PagedList<TSource>, PagedList<TDestination>>
{
    private readonly IMapper _mapper;

    public PagedListConverter(IMapper mapper)
    {
        _mapper = mapper;
    }

    public PagedList<TDestination> Convert(PagedList<TSource> source, PagedList<TDestination> destination, ResolutionContext context)
    {
        var destinationItems = _mapper.Map<List<TDestination>>(source);
        return new PagedList<TDestination>(destinationItems, source.TotalCount, source.CurrentPage, source.PageSize);
    }
}

然后在AutoMapper配置中注册转换器:

CreateMap(typeof(PagedList<>), typeof(PagedList<>))
    .ConvertUsing(typeof(PagedListConverter<,>));

同时确保已经配置了TSource到TDestination的基础映射(比如Category到CategoryDTO)。

方案3:修改PagedList结构,避免继承List

原PagedList<T>继承自List<T>,AutoMapper在处理继承自集合的类型时容易出现冲突。可以修改PagedList,将内部集合作为属性而非继承:

public class PagedList<T>
{
    public List<T> Items { get; set; }
    public int CurrentPage { get; set; }
    public int TotalPages { get; set; }
    public int PageSize { get; set; }
    public int TotalCount { get; set; }

    public bool HasPrevious => CurrentPage > 1;
    public bool HasNext => CurrentPage < TotalPages;

    public PagedList(List<T> items, int count, int pageNumber, int pageSize)
    {
        Items = items;
        TotalCount = count;
        PageSize = pageSize;
        CurrentPage = pageNumber;
        TotalPages = (int)Math.Ceiling(count / (double)pageSize);
    }
}

之后配置AutoMapper映射时,只需要配置基础的Category到CategoryDTO,以及PagedList<Category>到PagedList<CategoryDTO>,AutoMapper会自动映射Items属性和其他分页属性。


内容的提问来源于stack exchange,提问作者Nayala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 02:37:14