`
bk_lin
  • 浏览: 346542 次
社区版块
存档分类
最新评论

Table Storage对分页的支持

 
阅读更多

公告:本博客为微软云计算中文博客的镜像博客。部分文章因为博客兼容性问题,会影响阅读体验。如遇此情况,请访问原博客


大家可能知道WCF Data Services最新版提供了server paging的功能,意即在服务期端对数据进行分页,从而限制传回客户端的数据量。那么Windows Azure table storage是否提供分页功能呢?

Windows Azure table storage本身就限制了客户端一次性可以访问的数据量不能超过100条。当你需要访问的数据量超过100条时,只有前100条数据会被返回至客户端。同时response会包含一个x-ms-continuation-NextPartitionKey和x-ms-continuation- NextRowKey (通称continuation token),它代表着第101条数据的key。在后续的请求中,你可以将之前或取得continuation token通过query string传递给table storage,从而取得第101至第200条数据。

同理,当你使用take这个query string强制限制返回的数据量时,continuation token也会被包含于response中。

使用过新版本WCF Data Services的server paging功能的用户应该清楚如何在客户端程序中控制continuation token,从而对数据进行分页。在table storage中,你也可以使用类似的方式。只不过用法稍有不同。有关continuation token的基本用法,请参考http://blog.smarx.com/posts/windows-azure-tables-expect-continuation-tokens-seriously

然而你或许很快会发现server paging的局限性。是的,server paging的作用主要在于限制客户端一次性可以访问的数据量,而不在于帮助客户端构建起分页导航的功能。通过continuation token,你可以方便地取得下一个页面的数据。但是如果你要反过来取得之前一个页面的数据,就不那么简单了……

通常客户端的分页导航功能需要client paging来实现。例如,在WCF Data Services中,你可以通过skip和take这样的query string来要求服务返回从特定的起始点到特定的终结点的数据。然后很遗憾,table storage是不支持skip的,于是也就无法完整地使用client paging。

一个部分的解决方法是,你必须手工保存一个continuation token的列表。只要有了continuation token,我们就可以要求table storage从特定的记录开始返回。至于如何保存continuation token的列表,方式是多种多样的。以下演示如何将历史记录信息存储在cookie中,从而在ASP.NET中实现分页导航功能。

MVC的controller(控制导航逻辑):

publicActionResultIndex()

{

//使用JSONcontinuation token的历史信息存储到cookie中。

stringhistoryString =null;

if(Request.Cookies["history"] !=null)

{

historyString = Request.Cookies["history"].Value;

}

using(MemoryStreamstream =newMemoryStream())

{

using(StreamWriterwriter =newStreamWriter(stream))

{

writer.Write(historyString);

writer.Flush();

DataContractJsonSerializerserializer =newDataContractJsonSerializer(typeof(List<string>));

List<string> history =null;

try

{

stream.Position = 0;

//JSON返序列化。

history = serializer.ReadObject(stream)asList<string>;

}

catch

{

}

if(history ==null)

{

history =newList<string>();

}

StorageCredentialsAccountAndKeycredential =newStorageCredentialsAccountAndKey("[account]","[key]");

CloudStorageAccountaccount =newCloudStorageAccount(credential,false);

CloudTableClienttableClient =newCloudTableClient(account.TableEndpoint.ToString(), account.Credentials);

CustomerServiceContextctx =newCustomerServiceContext(account.TableEndpoint.ToString(), account.Credentials);

varquery = (DataServiceQuery<Customer>)(ctx.Customer.Take(10));

//currentPage传入query string

stringcurrentPage = Request["currentPage"];

intcurrentPageNumber = 0;

if(!string.IsNullOrEmpty(currentPage))

{

currentPageNumber =int.Parse(currentPage);

}

// action表明用户想要导航至上一页,从历史记录中取得对应的continuation token

stringaction = Request["action"];

if(action =="previous")

{

currentPageNumber--;

if(currentPageNumber != 0)

{

string[] tokens = history[currentPageNumber].Split('/');

varpartitionToken = tokens[0];

varrowToken = tokens[1];

query = query

.AddQueryOption("NextPartitionKey", partitionToken)

.AddQueryOption("NextRowKey", rowToken);

}

}

// action表明用户想要导航至上一页,从历史记录中取得对应的continuation token

elseif(action =="next")

{

currentPageNumber++;

stringcontinuation = Request["ct"];

if(continuation !=null)

{

string[] tokens = continuation.Split('/');

varpartitionToken = tokens[0];

varrowToken = tokens[1];

query = query

.AddQueryOption("NextPartitionKey", partitionToken)

.AddQueryOption("NextRowKey", rowToken);

}

}

varres = query.Execute();

varqor = (QueryOperationResponse)res;

stringnextPartition =null;

stringnextRow =null;

qor.Headers.TryGetValue("x-ms-continuation-NextPartitionKey",outnextPartition);

qor.Headers.TryGetValue("x-ms-continuation-NextRowKey",outnextRow);

if(nextPartition !=null&& nextRow !=null)

{

ViewData["continuation"] =string.Format("{0}/{1}", nextPartition, nextRow);

}

varresult = res.ToList();

varfirstEntity = result.First();

//将新的continuation token添加到历史记录中,如果它尚不存在的话……

stringhistoryEntry =string.Format("{0}/{1}", firstEntity.PartitionKey, firstEntity.RowKey);

if(!history.Contains(historyEntry))

{

history.Add(historyEntry);

}

//序列化成JSON

stream.Position = 0;

serializer.WriteObject(stream, history);

stream.Position = 0;

using(StreamReaderreader =newStreamReader(stream))

{

historyString = reader.ReadToEnd();

Response.Cookies.Add(newHttpCookie("history", historyString));

}

ViewData["currentPageNumber"] = currentPageNumber;

ViewData["result"] = result;

returnView();

}

}

}

MVC的view(显示Previous/Next导航):

<ahref='?currentPage=<%=ViewData["currentPageNumber"]%>&action=previous'>Previous</a>

<ahref='?ct=<%=ViewData["continuation"]%>&currentPage=<%=ViewData["currentPageNumber"]%>&action=next'>Next</a>

当然,这种方式也是有局限性的。例如,用户无法从中间某个页面开始访问数据,必须从第一页开始访问,从而能够建起一个continuation token的历史记录。由于table storage不支持count,我们也无法显示总共有几个页面。这是server paging的局限性,通常server paging被用于限制客户端一次性最多能访问多少数据,从而避免一些可能因数据量太多而发生的问题(诸如连接超时)。要构建起完整的分页导航功能,还需要client paging的支持。然而在目前table storage只支持server paging的情况下,上述解决方案让你能够构建起基本的分页导航功能。

分享到:
评论

相关推荐

    Eklee-Azure-Functions-GraphQl:通过依赖项注入在Azure上实现无服务器GraphQl,并支持Azure Cosmos DB,Azure Search和Azure Table Storage的解析器

    建议使用0.32及更高版本,因为0.31不支持分页,并且在0.32中解决了此问题。 DateTime现在返回ISO 8601格式。 我们现在使用.NET Standard 2.1。 努吉特 您可以在nuget上找到此库: ://...

    oracle增删改及分页存储过程

    Oracle数据库是一种广泛应用于企业级应用的数据管理解决方案,它支持丰富的数据类型、高级的查询功能以及存储过程等程序设计元素。存储过程是预编译的SQL和PL/SQL代码集合,可提高性能、简化管理和增强安全性。在...

    ASP MVC5和Azure表存储脚手架

    不同于传统的SQL数据库,Azure Table Storage提供键/值对存储,支持大规模数据存储,并且提供了高可用性和可伸缩性。要使用它,我们需要创建一个表服务客户端,定义实体类(继承于TableEntity),并使用Entity ...

    oracle 技巧

    TRUNCATE TABLE table_name REUSE STORAGE; ``` **13. 查看表结构** - **语法**: ```sql DESC table_name; ``` **14. 删除表** - **语法**: ```sql DROP TABLE table_name; ``` **15. 插入数据** -...

    Oracle事例

    14、查询从多少行到多少行的记录(可以用在web开发中的分页显示) select * from ( select rownum row_id,b.* from (select a.* from sys_oper a) b ) where row_id between 15 and 20 15、对公共授予访问权 ...

    ios-数据存储.zip

    HSKStorage不仅提供了基本的数据操作,还支持事务处理、条件查询、排序和分页等功能,让开发者能够更专注于业务逻辑,而不是数据库的底层细节。 总结来说,HSKStorage是iOS开发中一个实用的数据存储解决方案,尤其...

    boot:常用的工具或者服务

    参考了dubbo的SPI机制,也提供了支持spring的mybatis-plugin结合原生mybatis,以最小依赖,简单方便的使用通用mapper以及排序分页具体使用请参照boot-storage对象存储临时Token生成服务,支持S3协议对象存储客户端...

    HTML5本地存储——Web SQL Database

    IndexedDB提供类似的关系型数据存储,而Web Storage则更简单,适合存储键值对。 10. **安全性**:用户数据存储在本地意味着安全性问题。开发者需要注意数据加密,防止恶意攻击或数据泄露。 总之,Web SQL Database...

    Android 40 道面试题及答案.docx

    TableLayout 是表格布局,每一个 TableLayout 里面有表格行 TableRow,TableRow 里面可以具体定义每一个元素。 Android 中的动画有两种:Tween 动画和 Frame 动画。Tween 动画可以使视图组件移动、放大、缩小以及...

    Extjs2.0一些例子

    它支持分页、排序、过滤和行编辑等功能,是展示和管理数据的理想选择。 5. **表单(Form)组件**:ExtJS 2.0提供了一系列的表单组件,如文本框、下拉列表、复选框等,以及表单布局和验证功能。这使得创建交互式表单...

    数据存储1

    `query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)`: 增加了`limit`参数,用于控制查询结果的数量,常用于分页。...

    112-演示文稿-段式存储管理和示例.pdf

    内存分配机制可以动态地分配内存,解决 dynamic storage-allocation 问题。重定位机制可以实现动态重定位,借助段表实现。内存共享机制可以实现进程间代码共享,以“段”为最小单位。 Intel i386 处理器使用段式...

    oracle Blob

    CREATE TABLE tLob ( no NUMBER(4), name VARCHAR2(10), resume CLOB, photo BLOB, record BFILE ) Lob (resume,photo) Store As (Tablespace ts5_21 Chunk 6k Disable Storage In Row); ``` 2. 插入Blob...

    oracle基础练习

    - **知识点**: 使用 `add_months` 函数对日期进行加月操作。 - **示例**: ```sql select add_months(sysdate, 24) from dual; ``` - **解释**: 此查询返回当前日期后24个月的日期。 #### 16. Connect String的...

    Laravel开发-tatooine .zip

    - Laravel支持JSON响应、认证、分页等,是构建RESTful API的强大工具。 18. **测试**: - Laravel的PHPUnit集成使得编写单元测试和功能测试变得简单,有助于保证代码质量。 这个"laravel开发-tatooine .zip"项目...

    oracle命令

    这条命令用于对结果集进行分页处理,其中`n`为页码限制值。 #### 数据操纵语言(DML) 1. **插入数据**: ```sql INSERT INTO a VALUES (1); ``` 这条命令用于向表`a`中插入一行新记录。 2. **更新数据**: ...

    mysql面试题30道

    InnoDB 是 MySQL 的默认存储引擎,它支持事务和锁机制,适合高并发和事务处理场景。MyISAM 则是一种非事务型存储引擎,适合读取密集型应用场景。 什么是事务?MySQL 中如何实现事务? 事务是指一系列的数据库操作...

Global site tag (gtag.js) - Google Analytics