找回密码
 立即注册

QQ登录

只需一步,快速开始

断天涯大虾
社区贡献组   /  发表于:2016-8-2 11:45  /   查看:3540  /  回复:0
本帖最后由 断天涯大虾 于 2016-11-16 17:53 编辑

本文是在Azure Table storage 基本用法一文的基础上,介绍如何自定义 Azure Table storage 的查询过滤条件。如果您还不太清楚 Azure Table storage 的基本用法,请先移步前文

让我们回到前文中提到的一个问题,如何过滤出 MyLogTable 表中某一天产生的所有日志?在进入细节之前,我们先来回顾一下 MyLogTable 类的设计:

  1. <font face="微软雅黑" size="3" color="#000000"><blockquote>internal class MyLogEntity : TableEntity</font>
复制代码

其中,PartitionKey 用来存放产生日志的年份和月份(例如201607表示2016年7月),RowKey 用来存放产生日志的天和时分秒毫秒(例如160934248492表示16号9点34分…)。

在我们设计的 MyLogTable 中,天信息保存在 RowKey 的前两位。我们要做的就是过滤 RowKey 的前两位,也就是找到所有 RowKey 以”xx”开头的记录。这在字符串操作中称为 StartsWith。遗憾的是现有 Table storage 的接口中没有提供这种功能的方法,因此我们需要我们自己实现它(还好 TableQuery 的实现支持我们去扩展它)。

本文将通过实现 StartsWith 过滤条件说明如何自定义 Azure Table storage 的查询过滤条件。


TableQuery类

TableQuery 是本文的主角,它代表了 Table 上的一个查询。基本用法是使用查询条件构建一个 TableQuery 类的实例,然后把这个实例作为参数传递给 CloudTable 的 ExecuteQuery 方法:

  1. <font face="微软雅黑" size="3" color="#000000"><blockquote>TableQuery<MyLogEntity> query = new TableQuery<MyLogEntity>().Where(</font>
复制代码

我们还可以使用 TableQuery 的静态方法 CombineFilters 构建自定义的查询条件。
比如我们要查询 PartitionKey 等于 "201607" 并且 RowKey 等于"161148372454"的记录:

  1. <font face="微软雅黑" size="3" color="#000000"><blockquote>TableQuery.CombineFilters(</font>
复制代码

此时函数的返回结果为: ” (PartitionKey eq '201607') and (RowKey eq '161148372454')”。

然后把这个过滤字符串送给 query.Where 函数做参数,或者设置给 query.FilterString 属性,就可以完成过滤功能了。

CombineFilters 方法可爱的地方在于我们可以不断的使用它来合并查询条件,直到满意为止!

接下来我们一起看看 StartsWith 过滤条件的实现过程。


比较字符串

如何从一些字符串中找出以某个子串开头的字符串呢?我们可以从字符串的比较入手。

比如字符串具有下面的关系:

“abc”  ==  “abc” < “abd”

“abc” < “abca” < “abd”

“abc” < “abcz” < “abd”

由上面的大小关系我们可以得出结论:以”abc”开头的字符串必定大于或等于”abc”且小于”abd”。OK,这就是我们构建 StartsWith 过滤条件的理论基础。


构建StartsWith过滤条件

接下来我们通过 TableQuery.CombineFilters 方法构建 StartsWith 过滤条件:

  1. <font face="微软雅黑" size="3" color="#000000"><blockquote>string startsWithCondition = TableQuery.CombineFilters(</font>
复制代码

TableQuery.CombineFilters 方法的返回值是一个字符串。运行上面的代码我们会得到字符串:

“(RowKey ge 'abc') and (RowKey lt 'abd')”

我们完全可以手动拼出这样的字符串,但我相信没有程序员愿意这么做。

那么,我们需要继续完善上面的方法:

  1. <font face="微软雅黑" size="3" color="#000000"><blockquote>string startStr = "abc";</font>
复制代码

组合更多过滤条件

在前面构建 StartsWith 过滤条件时,我们已经使用 TableQuery.CombineFilters 方法组合了不同的过滤条件。遗憾的是 TableQuery.CombineFilters 方法只有两个参数的重载,我们不能添加更多的 TableOperators 操作。

但我们可以继续调用 TableQuery.CombineFilters 方法来组合上一个结果和新的条件。比如我们要把 Startswith 过滤条件和 PartitionKey 过滤条件组合起来就可以这么做:

  1. <font face="微软雅黑" size="3" color="#000000"><blockquote>string filterCondition = TableQuery.CombineFilters(</font>
复制代码

运行上面的代码,生成的结果为:

(PartitionKey eq '201607') and ((RowKey ge 'abc') and (RowKey lt 'abd'))

到这来就很清楚了,TableQuery.CombineFilters 方法的主要工作,就是把过滤条件组织成查询引擎能够识别的字符串。

因而我们可以通过不断的叠加,来生成很复杂的过滤条件。


封装StartsWith过滤条件

下面我们把 StartsWith 的逻辑封装到 StartsWithByRowKey 类型中,以下是完整的代码:

  1. <font face="微软雅黑" size="3" color="#000000"><blockquote>public class MyLogEntity : TableEntity</font>
复制代码

应用StartsWith的实例

现在查询 PartitionKey 为”201607”,RowKey 以”16”开头的记录可以这么写:

  1. <font face="微软雅黑" size="3" color="#000000">StartsWithByRowKey myStartsWithQuery = new StartsWithByRowKey("201607", "16");
  2. List<MyLogEntity> result = myStartsWithQuery.Execute(logTable);</font>
复制代码

代码简洁了很多,读起来也更清晰了(您还可以动手给 PartitionKey 也添加同样的功能)!


小结一下,本文简单的介绍了 TableQuery 类型,然后比较详细的说明了 StartsWith 过滤条件的思路及实现。主要是想通过 StartsWith 的实现来说明如何利用现有的类型和方法来实现自定义查询的过滤条件。对于有类似需求的朋友,希望能起到抛砖引玉的作用。


关于葡萄城

葡萄城成立于1980年,是全球最大的控件提供商,世界领先的企业应用定制工具、企业报表和商业智能解决方案提供商,为超过75%的全球财富500强企业提供服务。葡萄城于1988年在中国设立研发中心,在全球化产品的研发过程中,不断适应中国市场的本地需求,并为软件企业和各行业的信息化提供优秀的软件工具和咨询服务。

部分控件产品(点击图片查看)
AR1_副本.png
c11_副本.png
Spread1_副本.png
wijmo_副本.png
   
关于葡萄城:全球最大的控件提供商,世界领先的企业应用定制工具、企业报表和商业智能解决方案提供商,为超过75%的全球财富500强企业提供服务。

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部