【问题标题】:Server-Side Paging for improve performance用于提高性能的服务器端分页
【发布时间】:2018-04-28 08:25:33
【问题描述】:

我在 https://www.npmjs.com/package/ngx-pagination 的文档中一步一步地遵循了 Pagination for Angular 的说明。 我的分页工作完美,我对此没有任何问题。但是,由于我正在使用大型数据集 - 我不想使用内存中的完整集合,并且需要某种服务器端分页,服务器一次只发送一个页面。如那篇文章所述,我应该使用totalItems 参数并使用计数,但我不知道如何?我应该如何设置total

<table class='table' *ngIf="collection">
<tbody>
 <tr *ngFor="let item of collection | 
       paginate: { itemsPerPage: 10, currentPage: p, totalItems: total  }">
        <td>{{ item.id }}</td>
        <td>{{ item.name }}</td>
    </tr>
</tbody>

而我的WEB API是这样的:

[HttpGet("[action]")]
public async Task<IEnumerable<MyClass>> MyMethod()
{
    int perPage = 10;
    int start = (page - 1) * perPage;
    int end = start + perPage;

    using (HttpClient client = new HttpClient())
    {
        client.BaseAddress = new Uri("externalAPI");
        MediaTypeWithQualityHeaderValue contentType =
            new MediaTypeWithQualityHeaderValue("application/json");
        client.DefaultRequestHeaders.Accept.Add(contentType);
        HttpResponseMessage response = await client.GetAsync(client.BaseAddress);
        string content = await response.Content.ReadAsStringAsync();
        List<MyClass> data = JsonConvert.DeserializeObject<List<MyClass>>(content);
        return data.Skip(start).Take(perPage).ToList();
    }
}

还有:

p: number = 1;
total: number;

http.get('url', {
    params: {
        page : this.p
   }
}).subscribe(result => {
    this.collections = result.json() as Collection[];
}, error => console.error(error));

【问题讨论】:

    标签: c# angular asp.net-web-api asp.net-core-mvc


    【解决方案1】:

    为了在服务器端进行分页,你需要有两件事:

    1. pageSize 或 itemsPerPage 在你的情况下
    2. pageNumber 这基本上是你的 currentPage

    您需要将这两个值发送到您的 webapi,以便它知道要返回什么数据。 它们将成为您操作的参数,然后您可以将它们传递给 webapi。

    您如何在 webapi 中进行分页,这取决于您的代码。如果您使用 EntityFramework,则可以直接使用 Take 和 Skip 方法。如果你有一个存储过程(如 T-SQL),你可以使用 Fetch 和 Offset 来完成。

    关于 pageNumber 的注意事项。您的 UI 上的第 1 页需要成为服务器端的第 0 页,因此当您的 UI 请求第 1 页时,这基本上是数据的第 0 页。第 2 页 UI 端,变成第 1 页数据端,所以你可能通过 pageNumber - 1 到后端。请记住这一点。

    totalItems 是一个来自后端的数字。 假设您的 Web api 返回如下所示的分页数据:

    public class myReturnedData
    {
        public string someData1 { get;set; }
        public string someData2 { get;set }
    }
    

    你的 api 基本上返回这个类的列表。

    此时创建另一个如下所示的对象:

    public class myPaginatedReturnedData
    {
        public List<myReturnedData> { get; set; }
    
        public int TotalItemsCount { get; set; }
    }
    

    您的前端无法知道总计数是多少,因为它只接收一页数据,因此您需要从 API 获取该数字,这是一种方法。

    因此,在您分页之前,在服务器端,您会对您的项目进行总计数,然后对数据进行分页,最后将这两个项目发回。

    在前端,您将拥有 pageSize 和 totalItemsCount,您可以使用它来计算应该向用户显示多少页面索引。

    如果您的 pageSize 为 10,totalItemsCount 为 55,那么您的页面索引将从 1 到 6,第 6 页仅显示 5 个项目。您可以轻松地在客户端编写一个方法来进行此计算。

    改变这个:

    public async Task<IEnumerable<MyClass>> MyMethod()
    

    public async Task<myPaginatedReturnedData> MyMethod()
    

    在我的示例中,我基本上已将您原来的返回类更改为新的类,它是您的包装器加上 totalCount 值。

    这允许您在前端设置值,因为您现在将它与实际的分页数据一起返回。

    在客户端,API 的响应将是一个字符串。

    您可以将响应字符串解析为 JSON 对象,使用类似

    var apiData = JSON.parse(responseString)
    

    这为您提供了一个对象,您可以从那里访问您的数据。

    【讨论】:

    • 很好的解决方案,但为什么要密封类?
    • 哦,你不必,这只是我的一个习惯,把所有不应该被扩展的东西都密封起来。如果不需要,请不要这样做。
    • 没关系,只是一个问题;)
    • 这是个好问题,我删除了它,因为它会引发与原始问题无关的其他讨论。
    • 感谢您的解释。我已经更改了我的代码,并根据你所说的和它的文档添加了一些代码。但是我仍然有前端的问题,我几乎完成了,只是我不知道我应该如何从客户端设置总变量。请检查我更新的问题。
    猜你喜欢
    • 2019-06-06
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    • 2021-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-18
    相关资源
    最近更新 更多