如何使用OData对azure表存储API进行分页?

时间:2013-10-07 13:28:43

标签: c# azure asp.net-web-api pagination odata

我的要求是做客户端分页。即根据客户给出的值($ top,$ skip)返回一组记录。但根据我的下面的代码,我只能使用filter关键字和top或skip。

[HttpGet]        
public PageResult<PersistedUser> GetAllUsers(ODataQueryOptions options)
{
    TableServiceContext serviceContext = tableClient.GetDataServiceContext();
    serviceContext.IgnoreResourceNotFoundException = true;

    CloudTableQuery<PersistedUser> users = serviceContext
        .CreateQuery<PersistedUser>(TableNames.User)
        .AsTableServiceQuery();    

    IQueryable<PersistedUser> results = options
        .ApplyTo(users.AsQueryable()) as IQueryable<PersistedUser>;

    // manipulate results. Add some calculated variables to the collection etc

    return new PageResult<PersistedUser>(results, null, 0);
}

我不确定这是否也是正确的做法。但我的基本要求是我有一个巨大的数据库,但我只需要在一个有效的时间内一次返回一小组实体。如果有人能提供一些代码片段,我将非常感激。

3 个答案:

答案 0 :(得分:0)

我使用相同的方式,它工作正常。

几乎没有差异:

我有一个服务层,可以揭露我的真实情况。在我的服务中,我返回IQueryable并应用O Data过滤器。

    [AuthKey]
    [GET("api/brands/")]
    public PageResult<BrandViewModel> GetBrands(ODataQueryOptions<Brand> options)
    {
        var brands = (IQueryable<Brand>)options.ApplyTo(_brandServices.FindBrands());

        return new PageResult<BrandViewModel>(BrandViewModel.ToViewModel(brands), Request.GetNextPageLink(), Request.GetInlineCount());
    }

答案 1 :(得分:0)

以下是使用通用版ODataQueryOptions的代码的更新版本,并应用$top$skip选项进行分页。

[HttpGet]        
public PageResult<PersistedUser> GetAllUsers(
    ODataQueryOptions<PersistedUser> options)
{
    TableServiceContext serviceContext = tableClient.GetDataServiceContext();
    serviceContext.IgnoreResourceNotFoundException = true;

    CloudTableQuery<PersistedUser> users = serviceContext
        .CreateQuery<PersistedUser>(TableNames.User)
        .AsTableServiceQuery();    

    IQueryable<PersistedUser> results = options.ApplyTo(users);

    int skip = options.Skip == null ? 0 : options.Skip.Value;
    int take = options.Top == null ? 25 : options.Top.Value;

    return new PageResult<PersistedUser>(
        results.Skip(skip).Take(take).ToList(), 
        Request.GetNextPageLink(),
        null);
}

答案 2 :(得分:0)

规划OData模型时,请将其与底层存储模型分开。在某些域中,可能会公开组,然后使用导航属性来访问组的成员。

例如,假设您有预订系统。您可以按日期时间将预订存储在长而长的表格中。

但是你可以通过分组成年和周的集合来暴露OData模型。

http://service.net/odata/year(2013)/week(22)/bookings

在您的控制器中,您可以根据提供的时间参数撰写表存储范围查询。

如果有> 1,000次预订,但数量不多,您可以在服务器端浏览它们,耗尽集合,并将所有预订交还给OData客户端,或者对它们进行排序并允许IQueryable组。见注释,底部。

这将为OData消费者提供一种过滤数据的自然机制,同时保持较低的结果集大小。如果每周有许多预订,则可以按星期和小时进一步细分。

这完全是理论上的,但我认为OData v4及其包含功能将允许路由这些URL并描述关系,以便为像Excel这样的OData消费者生成正确的元数据。

http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/odata-containment-in-web-api-22

请注意,在上面的示例代码中,他们创建了一个用于计算所包含项目的任意路由/ URL,因此它似乎很灵活。

如果不允许嵌套包含,则可以考虑在OData EDM中使用Year和Week属性的BookingRange实体允许:

http://service.net/odata/bookingrange(2013,22)/bookings

我考虑的另一个想法是在插入时计算页码。也就是说,在TS实体本身上有一个PageNumber,并使用算法为其分配页码。这与生成一个好的分区键基本相同,但是有很多页/分区。

一个预计容纳200米行的表可以有1米的页面(生成一个大的伪随机数并将其修改为1米),每个包含200个项目。首先,大多数页面都是空的,因此您需要编写一个页面映射算法,随着行数的增加而改变。 &#34;页&#34; 1映射到页面范围0000001 - 0000100等

正如您所看到的,这变得越来越复杂,但它本质上与Azure一样,用于跨分区自动平衡数据并在其节点之间传播这些分区。

最终,这将再次需要一种方式来对抗&#34; Page&#34;要在URL中指定的号码。最后,每个页面将包含不同数量的项目,具体取决于所用算法的分布。

注意 - 我认为TS不支持top和skip或skip的原因是返回的行的顺序无法保证并且TS中没有排序机制(这将是是一个很大的负担)。因此,从top和skip整理的页面将包含&#34; random&#34;每次都包。

这意味着我上面提到的对一个子集/数据组进行分页的建议要求在应用top和skip之前将整个子集带入服务层并应用排序顺序,尽管它可能是认为客户应该明白没有订单的顶部/跳过是没有意义的,他们有责任发送正确的选项。