服务器端分页以提高性能

时间:2018-04-28 08:25:34

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

我在其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));

1 个答案:

答案 0 :(得分:2)

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

    您的案例中
  1. pageSize或 itemsPerPage
  2. pageNumber基本上是您的 currentPage
  3. 您需要将这两个值发送到您的webapi,以便它知道要返回的数据。 它们将成为您操作的参数,然后您可以将它们传递给webapi。

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

    pageNumber上的注意事项。您的UI上的页面1需要成为服务器端的第0页,因此当您的UI请求第1页基本上是数据的第0页时。 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个项目。您可以在客户端轻松编写方法进行此计算。

    &lt; - 额外详情 - &gt;

    改变这个:

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

    public async Task<myPaginatedReturnedData> MyMethod()
    

    我基本上已将原来的返回类更改为我的示例中的新类,这是你的包装器加上t​​otalCount值。

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

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

    您可以使用类似

    之类的内容将响应字符串解析为JSON对象
    var apiData = JSON.parse(responseString)
    

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