公告:本博客为微软云计算中文博客的镜像博客。部分文章因为博客兼容性问题,会影响阅读体验。如遇此情况,请访问原博客。
大家可能知道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()
{
//使用JSON将continuation 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"]%>¤tPage=<%=ViewData["currentPageNumber"]%>&action=next'>Next</a>
当然,这种方式也是有局限性的。例如,用户无法从中间某个页面开始访问数据,必须从第一页开始访问,从而能够建起一个continuation token的历史记录。由于table storage不支持count,我们也无法显示总共有几个页面。这是server paging的局限性,通常server paging被用于限制客户端一次性最多能访问多少数据,从而避免一些可能因数据量太多而发生的问题(诸如连接超时)。要构建起完整的分页导航功能,还需要client paging的支持。然而在目前table storage只支持server paging的情况下,上述解决方案让你能够构建起基本的分页导航功能。
分享到:
相关推荐
本文实例讲述了bootstrap-table后端分页功能。分享给大家供大家参考,具体如下: 使用bootstrap-table实现后台分页 插件资源点击此处本站下载。 引用以下css <link rel="stylesheet" href="../plugins/...
bootstrap-table客户端分页实例,数据源为前端数据,用于测试json数据填充后,形成表格数据类型,初级入门~
table排序和分页table排序和分页table排序和分页table排序和分页table排序和分页
通过修改bootstrap table js 定制出自己的分页栏,样式仿照jqGrid样式,支持输入页码跳转
bootstrap-table是基于 bootstrap与query的分页框架,支持前端分页与后端分页,支持前端数据导出(word、excel、sql、json、pdf等)
SETCount的存储过程分页,支持Sorting
绑定table数据进行分页,里面的sql.txt文件是分页套用的公式。
js实现table分页可以动态生成table
bootstrap-table动态加载json数据并且支持分页。摘要必须大于50个字节!
按照table行进行分页
easyui-table客户端分页,数据源为前端数据
bootstrap-table后端分页的参数设置Demo。 bootstrap-table是一款非常有名的开源表格插件,在很多项目中广泛的应用。Bootstrap-table插件提供了非常丰富的属性设置,可以实现查询、分页、排序、复选框、设置显示列、...
bootstrap table分页例子 bootstrap table实现了2种分页方式。
js-table分页
[MVC]bootstrap-table表格ajax获取json数据并分页。
js_table分页,利用js分页 比较简单一些吧!!不用再用sql查询出来分页,但是缺点是影响性能!
主要介绍了利用js制作html table的分页示例(js实现分页),需要的朋友可以参考下
html table page
jQuery实现Table分页跳转,JQUERY实现TABLE分页效果
js+table分页实现,压缩包里有一个.html文件一个jQuery包,下载后可直接打开html文件,实现的功能包括:当前页、数据总量、页数、首页、上一页、下一页、尾页、页数跳转,只是功能实现没写css做美化