【问题标题】:How to use OData to do pagination on azure table storage APIs?如何使用 OData 对 Azure 表存储 API 进行分页?
【发布时间】:2023-04-03 08:58:01
【问题描述】:

我的要求是做客户端分页。即根据客户端给出的值($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);
}

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

【问题讨论】:

  • 您可能要记住的一件事是,表存储本身并不支持所有 OData 功能(例如不支持 $skip),因此您需要在服务层中自行管理它.
  • 是的,我知道表存储不支持所有这些操作。这就是为什么我想知道该怎么做。如果我获取所有结果并将它们转换为列表,然后应用 OData 选项,那么它不是有效的权利。获取 20 条记录所需的时间与获取 1000 条记录所需的时间相同。知道为 API 实现分页的有效方法吗?
  • 我认为您可能需要回到绘图板上,看看您是否需要以不同于您今天所做的方式来存储数据以完成 OData 功能。如果数据存储在一起,那么我认为您唯一的选择是从表中获取所有数据并在您的服务层中应用这些 OData 过滤器,这对于较小的数据集可能不是问题,但一旦您的数据将是一个大问题集合变大了。

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


【解决方案1】:

我用的是同样的方法,效果很好。

区别不大:

我有一个暴露我的实体的服务层。在我的服务中,我返回 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());
    }

【讨论】:

【解决方案2】:

这是您的代码的更新版本,它使用通用版本的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);
}

【讨论】:

  • 我还是得到请求的操作没有在指定的资源上实现错误
  • @Bitsian 尽管它在标题中,但我无法理解这是关于“表存储”的事实。
  • 关于如何在 azure 表存储上进行分页的任何想法?这对使用表存储来说是一个巨大的挫折:(
  • @Bitsian 你能在var usersvar results 更新你的代码,将var 更改为实际的数据类型吗?
  • 抱歉耽搁了。我已经用实际的数据类型进行了编辑。如果您能想到解决方案,请告诉我
【解决方案3】:

在规划 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,并使用一种算法为其分配一个页码。这与生成一个好的分区键基本相同,但具有许多页面/分区。

一个期望包含 200m 行的表可能有 1m 个页面(生成一个大的伪随机数并将其修改 1m),每个页面包含 200 个项目。起初,大多数页面都是空的,因此您需要编写一个页面映射器算法,该算法会随着行数的增长而改变。 “页面”1 映射到页面范围 0000001 - 0000100 等。

如您所见,这变得越来越复杂,但它本质上与 Azure 用于跨分区自动平衡数据并将这些分区分布在其节点中的系统相同。

最终,这将再次需要一种在 URL 中指定“页”号的方法。最后,每个页面将包含不同数量的项目,具体取决于所使用算法的分布。

注意 - 我认为 TS 不支持 top 和 skip 或 skip 的原因是无法保证返回的行的顺序,并且 TS 内没有排序机制(这将成为很大的负担)。因此,从顶部整理和跳过的页面每次都会包含一个“随机”包。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-08
    • 1970-01-01
    • 2012-05-29
    • 2012-06-08
    • 2016-11-12
    • 2021-06-02
    相关资源
    最近更新 更多