简体   繁体   English

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

[英]How to use OData to do pagination on azure table storage APIs?

Well my requirement is to do client side paging. 好吧,我的要求是进行客户端分页。 ie return a set of records based on the values($top, $skip) given by client. 即根据客户端给定的值($ top,$ skip)返回一组记录。 But based on my below code, am able to use only filter keyword and top or 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);
}

I am not really sure if this is the correct way to do it as well. 我不太确定这是否也是正确的方法。 But my basic requirement is that I have a huge db, but i just need to return a small set of entities at a time in an efficient time. 但是我的基本要求是我有一个巨大的数据库,但是我只需要在有效时间内一次返回一小部分实体。 I would really appreciate if someone could provide some code snippets. 如果有人可以提供一些代码片段,我将不胜感激。

I'm using the same way and it's working fine. 我正在使用相同的方式,并且工作正常。

Few differences: 差异不大:

I have a service layer that expose my entites. 我有一个服务层来展示我的实体。 In my services I return IQueryable and apply the O Data filter. 在我的服务中,我返回IQueryable并应用O数据过滤器。

    [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());
    }

Here's an updated version of your code that uses the generic version of ODataQueryOptions and applies the $top and $skip options for paging. 这是代码的更新版本,该代码使用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);
}

When planning your OData model, separate it from the underlying storage model. 计划OData模型时,请将其与基础存储模型分开。 In some domains it may be possible to exposed groups and then use navigation properties to access the members of the group. 在某些域中,可能可以公开组,然后使用导航属性访问该组的成员。

For example, suppose you have a booking system. 例如,假设您有一个预订系统。 You may store your bookings in a long, long table by date-time. 您可以按日期时间将预订存储在很长的桌子上。

But you could potentially expose the OData model by grouping into collections of year and week. 但是您可以通过分组为年和周的集合来公开OData模型。

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

In your controller, you'd compose a Table Storage range query from the temporal parameters supplied. 在您的控制器中,您将根据提供的时间参数组成一个表存储范围查询。

If there were >1,000 bookings, but not a huge number more, you could page through them server-side, exhaust the set, and deliver all the bookings back to the OData client, or sort them and allow IQueryable over this set. 如果有超过1,000个预订,但数量不多,则可以在服务器端通过它们进行分页,用尽所有设置,然后将所有预订传递回OData客户端,或者对它们进行排序并允许IQueryable使用该设置。 See note, bottom. 请参阅底部的注释。

This would afford the OData consumer a natural mechanism for filtering data while keeping result set sizes low. 这将为OData使用者提供一种自然的过滤数据机制,同时保持结果集大小较小。 Where there are many bookings per week, it could be sub-grouped further by day of week and hour. 每周有很多预订的地方,可以按星期几和小时数将其进一步细分。

This is completely theoretical, but I think OData v4 and its containment feature would allow such URLs to be routed and the relationship described so as to produce correct metadata for OData consumers like Excel. 这完全是理论上的,但是我认为OData v4及其包含功能将允许对此类URL进行路由并描述其关系,以便为OData使用者(如Excel)生成正确的元数据。

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

Note in the above sample code that they create an arbitrary route/URL for counting the contained items, so it seems flexible. 请注意,在上面的示例代码中,它们创建了一个任意的路由/ URL来对包含的项目进行计数,因此看起来很灵活。

If nested containment is not allowed, then alternatively, consider a BookingRange entity in the OData EDM with Year and Week properties to allow: 如果不允许嵌套包含,则可以考虑使用具有Year和Week属性的OData EDM中的BookingRange实体,以允许:

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

Another idea I've considered is calculating a page number on insert. 我考虑过的另一个想法是在插入时计算页码。 That is, to have a PageNumber on the TS entity itself and use an algorithm to assign a page number to it. 也就是说,在TS实体本身上具有PageNumber并使用算法为其分配页码。 This is essentially the same as generating a good partition key but with many pages/partitions. 这本质上与生成良好的分区键相同,但具有许多页面/分区。

A table expecting to hold 200m rows could have 1m pages (generate a large psuedo random number and Mod it by 1m), each with 200 items. 预期容纳200m行的表可能具有100万个页面(生成一个大的伪随机数并将其修改为1m),每个页面包含200个项目。 At first, most pages would be empty, so you'd need to write a page mapper algo that alters as the row count grows. 首先,大多数页面将是空的,因此您需要编写一个页面映射器算法,该算法会随着行数的增加而改变。 "Page" 1 maps to page range 0000001 - 0000100, etc. “页面” 1映射到页面范围0000001-0000100,依此类推。

As you can see, this is getting complex, but its essentially the same system that Azure uses itself to auto-balance your data across partitions and spread those partitions across its nodes. 如您所见,这变得越来越复杂,但其本质上与Azure使用同一系统来跨分区自动平衡数据并将这些分区分布到其节点的系统相同。

Ultimately, this would again need a way for the "Page" number to be specified in the URL. 最终,这将再次需要一种在URL中指定“页面”编号的方法。 Finally, each page would contain varying numbers of items, depending on the distribution of the algorithm used. 最后,每个页面将包含不同数量的项目,具体取决于所使用算法的分布。

Note - I think the reason that TS does not support top and skip, or skip, is that the order of the rows returned cannot be guaranteed and there is no ordering mechanism within TS (which would be a big burden). 注意 -我认为TS不支持top和skip或skip的原因是不能保证返回的行的顺序,并且TS内没有排序机制(这将是一个很大的负担)。 Therefore, pages collated from top and skip would contain a "random" bag each time. 因此,从上到下跳过的页面每次都会包含一个“随机”包。

This means that my suggestion above to offer paging over a subset/group of data, requires that the entire subset is brought into the service tier and a sort order applied to them, before applying the top and skip, though it could be argued that the client should understand that top/skip without an order is meaningless and the onus is on them to send the right options. 这意味着我上面的建议是提供对一个子集/一组数据的分页,要求将整个子集带入服务层,并在应用顶部和跳过之前对它们应用排序顺序,尽管可能会认为客户应该理解,没有订单就没有顶/跳过是没有意义的,他们有责任发送正确的选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM