【问题标题】:Map entity pagination class to dto pagination class将实体分页类映射到 dto 分页类
【发布时间】:2019-01-04 07:08:44
【问题描述】:

我有以下 PaginatedList 类。

public class PaginatedList<T> : List<T>
{
    public int PageIndex { get; }
    public int TotalRecords { get; }
    public int TotalPages { get; }

    public PaginatedList(IEnumerable<T> items, int totalRecords, int pageIndex, int pageSize)
    {
        PageIndex = pageIndex;
        TotalRecords = totalRecords;
        TotalPages = (int)Math.Ceiling(TotalRecords / (double)pageSize);

        AddRange(items);
    }

    public bool HasPreviousPage => PageIndex > 1;

    public bool HasNextPage => PageIndex < TotalPages;

    public static async Task<PaginatedList<T>> CreateAsync(
        IQueryable<T> source, int pageIndex, int pageSize)
    {
        var count = await source.CountAsync();
        var items = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
        return new PaginatedList<T>(items, count, pageIndex, pageSize);
    }
}

我正在使用这个类来获取使用 EF 检索的实体列表的分页信息。

这就是我如何使用这个类返回带有分页信息的用户列表。

var users = await PaginatedList<User>.CreateAsync(userQuery, pageIndex, pageSize);

以上调用将返回PaginatedList&lt;User&gt; 对象。

如果我有该实体的 DTO 类,我们称它为 UserDto。如何使用 automapper 将 PaginatedList&lt;User&gt; 转换为 PaginatedList&lt;UserDto&gt; 以便结果将包含所有 userDto 对象以及分页信息?

否则,是否有另一种/更好的方法来实现类似的目标?

【问题讨论】:

  • List&lt;T&gt; 派生是一个非常糟糕的选择。我强烈推荐阅读Is-A Versus Has-A
  • @ErikPhilips 谢谢你的建议,我去看看
  • @ErikPhilips 为什么得出一个错误的选择?我认为 PaginatedList 是一个列表,但具有附加属性。
  • @user3049658 Why not inherit from List<T>。在这个问题的实现中,PageIndex 的属性不是 什么是列表也不是分页列表PageIndex 是 State 的属性,而不是 List 的属性。

标签: c# automapper


【解决方案1】:

我最终在 PaginatedList 中创建了另一个工厂方法来处理转换。

public static async Task<PaginatedList<TResult>> CreateAsync<TSource>(
    IQueryable<TSource> source, int pageIndex, int pageSize)
{
    Ensure.It.IsGreaterThan(0, pageIndex);
    Ensure.It.IsGreaterThan(0, pageSize);

    var count = await source.CountAsync();
    var items = await source.Skip((pageIndex - 1) * pageSize)
        .Take(pageSize)
        .Select(ufc => Mapper.Map<TResult>(ufc))
        .ToListAsync();
    return new PaginatedList<TResult>(items, count, pageIndex, pageSize);
}

然后让现有的CreateAsync 方法调用这个新的CreateAsync&lt;TSource&gt; 方法。

public static async Task<PaginatedList<TResult>> CreateAsync(
    IQueryable<TResult> source, int pageIndex, int pageSize)
{
    return await CreateAsync<TResult>(source, pageIndex, pageSize);
}

有了这个,如果我们想继续返回相同的Entity类,我们可以这样使用它

await PaginatedList<User>.CreateAsync(_dbContext.User.AsQueryable(), pageIndex, pageSize)

而如果我们想将实体类转换为返回Dto类或者其他类,可以这样使用

await PaginatedList<UserDto>.CreateAsync(_dbContext.User.AsQueryable(), pageIndex, pageSize)

如果我们不将实体转换为其他类,我们不需要在自动映射器配置中指定任何内容。但是如果要将实体映射到其他类,则需要在自动映射器中进行配置。

或多或少,这是 PaginatedList 类的样子

public class PaginatedList<TResult> : List<TResult>
{
    public int PageIndex { get; }
    public int TotalRecords { get; }
    public int TotalPages { get; }

    public PaginatedList(IEnumerable<TResult> items, int count, int pageIndex, int pageSize)
    {
        PageIndex = pageIndex;
        TotalRecords = count;
        TotalPages = (int)Math.Ceiling(TotalRecords / (double)pageSize);

        AddRange(items);
    }

    public bool HasPreviousPage => PageIndex > 1;

    public bool HasNextPage => PageIndex < TotalPages;

    public static async Task<PaginatedList<TResult>> CreateAsync<TSource>(
        IQueryable<TSource> source, int pageIndex, int pageSize)
    {
        var count = await source.CountAsync();
        var items = await source.Skip((pageIndex - 1) * pageSize)
            .Take(pageSize)
            .Select(ufc => Mapper.Map<TResult>(ufc))
            .ToListAsync();
        return new PaginatedList<TResult>(items, count, pageIndex, pageSize);
    }

    public static async Task<PaginatedList<TResult>> CreateAsync(
        IQueryable<TResult> source, int pageIndex, int pageSize)
    {
        return await CreateAsync<TResult>(source, pageIndex, pageSize);
    }
}

【讨论】:

    【解决方案2】:

    Automapper 非常适合我,但需要在 PaginatedList 类上创建默认构造函数

    public PaginatedList()
    {
        PageIndex = 0;
        TotalRecords = 0;
        TotalPages = 0;
    }
    

    -------------------------------- 示例

    class User
    {
        public string Name { get; set; }
    }
    
    class UserDto
    {
        public string NameDto { get; set; }
    }
    
    public class UserProfile: Profile
    {
        public UserProfile()
        {
            CreateMap<User, UserDto>()
                .ForMember(target => target.NameDto, x => x.MapFrom(source => source.Name))
                .ReverseMap();
        }
    }
    
    internal class Program
    {
       private static void Main(string[] args)
       {
           Mapper.Initialize(config =>
           {
               config.AddProfile<UserProfile>();
           });
    
           var items = new List<User> { new User { Name = "First name" } };
    
           var users = new PaginatedList<User>(items, 1, 0, 1);
    
           var usersDtos = Mapper.Map<PaginatedList<UserDto>>(users);
    
       }
    

    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-13
      • 2021-12-31
      • 1970-01-01
      • 1970-01-01
      • 2022-01-02
      相关资源
      最近更新 更多