文档章节

自定义 Azure Table storage 查询过滤条件

葡萄城技术团队
 葡萄城技术团队
发布于 2016/08/02 12:11
字数 1427
阅读 22
收藏 0

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

文章来源:葡萄城产品技术社区

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

internal class MyLogEntity : TableEntity
{
    public MyLogEntity() { }
    public MyLogEntity(string pkey, string rkey)
    {
        this.PartitionKey = pkey;
        this.RowKey = rkey;
    }
    //…
} 

其中,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 方法:

TableQuery<MyLogEntity> query = new TableQuery<MyLogEntity>().Where(
    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "201607"));
var queryResult = logTable.ExecuteQuery(query);

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

TableQuery.CombineFilters(
    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "201607"),
    TableOperators.And,
    TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, "161148372454"));

此时函数的返回结果为: ” (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 过滤条件:

string startsWithCondition = TableQuery.CombineFilters(
    TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.GreaterThanOrEqual, "abc"),
    TableOperators.And,
    TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThan, "abd")
    );

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

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

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

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

string startStr = "abc";
int endIndex = startStr.Length - 1;
Char lastChar = startStr[endIndex];
//找到比字符'c'大的那个字符。
Char afterLastChar = (char)(lastChar + 1);
//拼出字符串 "abd"
string endStr = startStr.Substring(0, endIndex) + afterLastChar;
string startsWithCondition = TableQuery.CombineFilters(
    TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.GreaterThanOrEqual, startStr),
    TableOperators.And,
    TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThan, endStr)
    );

 

组合更多过滤条件

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

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

string filterCondition = TableQuery.CombineFilters(
    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "201607"),
    TableOperators.And,
    "(RowKey ge 'abc') and (RowKey lt 'abd')"
    );

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

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

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

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

 

封装StartsWith过滤条件

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

public class MyLogEntity : TableEntity
{
     public MyLogEntity() { }
     public MyLogEntity(string pkey, string rkey)
     {
         this.PartitionKey = pkey;
         this.RowKey = rkey;
     }

     public DateTime LogDate { get; set; }
     public string LogMessage { get; set; }
     public string ErrorType { get; set; }
}

public class StartsWithByRowKey : IQuery<CloudTable, List<MyLogEntity>>
{
     private readonly string partitionKey;
     private readonly string startsWithString;

     internal StartsWithByRowKey(string partitionKey,
         string startsWithString)
     {
         this.partitionKey = partitionKey;
         this.startsWithString = startsWithString;
     }

     public List<MyLogEntity> Execute(CloudTable coludTable)
     {
         var query = new TableQuery<MyLogEntity>();

         int endIndex = startsWithString.Length - 1;
         Char lastChar = startsWithString[endIndex];
         Char afterLastChar = (char)(lastChar + 1);
         string endStr = startsWithString.Substring(0, endIndex) + afterLastChar;

         string startsWithCondition = TableQuery.CombineFilters(
             TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.GreaterThanOrEqual, startsWithString),
             TableOperators.And,
             TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThan, endStr)
             );

         string filterCondition = TableQuery.CombineFilters(
             TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey),
             TableOperators.And,
             startsWithCondition
             );

         var entities = coludTable.ExecuteQuery(query.Where(filterCondition));
         return entities.ToList();
     }
 }

 public interface IQuery<in TModel, out TResult>
 {
     TResult Execute(TModel model);
 }

 

应用StartsWith的实例

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

StartsWithByRowKey myStartsWithQuery = new StartsWithByRowKey("201607", "16");
List<MyLogEntity> result = myStartsWithQuery.Execute(logTable);

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

 

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

© 著作权归作者所有

共有 人打赏支持
葡萄城技术团队

葡萄城技术团队

粉丝 384
博文 539
码字总数 785880
作品 17
西安
高级程序员
私信 提问
Azure Table storage 基本用法

Azure Storage 是微软 Azure 云提供的云端存储解决方案,当前支持的存储类型有 Blob、Queue、File 和 Table,其中的 Table 就是本文的主角 Azure Table storage。 Azure Table storage 是一个...

葡萄城控件技术团队
2016/08/24
153
0
最全的Windows Azure学习教程汇总

Windows Azure 是微软基于云计算的操作系统,能够为开发者提供一个平台,帮助开发可运行在云服务器、数据中心、Web 和 PC 上的应用程序。 Azure 是一种灵活和支持互操作的平台,能够将处于云...

葡萄城控件技术团队
2016/11/08
35
0
最全的Windows Azure学习教程汇总

转载: http://blog.csdn.net/powertoolsteam/article/details/53082470 目录(?)[-] 一 Windows Azure 平台简介 二Windows Azure入门教学系列 三Azure学习笔记 四Azure Storage 基本用法介绍......

chenhao_asd
2017/02/26
0
0
Azure Blob Storage 基本用法 -- Azure Storage 之 Blob

Azure Storage 是微软 Azure 云提供的云端存储解决方案,当前支持的存储类型有 Blob、Queue、File 和 Table。 笔者在《Azure Table storage 基本用法》一文中,介绍了 Table Storage 的基本用...

葡萄城控件技术团队
2016/10/18
80
1
Azure Queue Storage 基本用法 -- Azure Storage 之 Queue

Azure Storage 是微软 Azure 云提供的云端存储解决方案,当前支持的存储类型有 Blob、Queue、File 和 Table。 笔者在《Azure File Storage 基本用法》中介绍了 File Storage 的基本用法,本文...

葡萄城控件技术团队
2016/11/01
148
1

没有更多内容

加载失败,请刷新页面

加载更多

Confluence 6 升级中的一些常见问题

升级的时候遇到了问题了吗? 如果你想尝试重新进行升级的话,你需要首先重新恢复老的备份。不要尝试再次对 Confluence 进行升级或者在升级失败后重新启动老的 Confluence。 在升级过程中的一...

honeymoose
今天
2
0
C++随笔(四)Nuget打包

首先把自己编译好的包全部准备到一个文件夹 像这样 接下来新建一个文本文档,后缀名叫.nuspec 填写内容 <?xml version="1.0"?><package xmlns="http://schemas.microsoft.com/packaging/201......

Pulsar-V
今天
2
0
再谈使用开源软件搭建数据分析平台

三年前,我写了这篇博客使用开源软件快速搭建数据分析平台, 当时收到了许多的反馈,有50个点赞和300+的收藏。到现在我还能收到一些关于dataplay2的问题。在过去的三年,开源社区和新技术的发...

naughty
今天
5
0
Python3的日期和时间

python 中处理日期时间数据通常使用datetime和time库 因为这两个库中的一些功能有些重复,所以,首先我们来比较一下这两个库的区别,这可以帮助我们在适当的情况下时候合适的库。 在Python文...

编程老陆
今天
2
0
分布式面试整理

并发和并行 并行是两个任务同时进行,而并发呢,则是一会做一个任务一会又切换做另一个任务。 临界区 临界区用来表示一种公共资源或者说是共享数据,可以被多个线程使用,但是每一次,只能有...

群星纪元
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部