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

本文是在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 的实现来说明如何利用现有的类型和方法来实现自定义查询的过滤条件。对于有类似需求的朋友,希望能起到抛砖引玉的作用。

 

相关阅读:

最全的Windows Azure学习教程汇总

Azure Blob Storage 基本用法 -- Azure Storage 之 Blob

Azure Queue Storage 基本用法 -- Azure Storage 之 Queue

Azure File Storage 基本用法 -- Azure Storage 之 File

Azure Table storage 基本用法 -- Azure Storage 之 Table

 

时间: 2024-10-31 04:56:44

自定义 Azure Table storage 查询过滤条件的相关文章

Azure Table storage 基本用法 -- Azure Storage 之 Table

Azure Storage 是微软 Azure 云提供的云端存储解决方案,当前支持的存储类型有 Blob.Queue.File 和 Table,其中的 Table 就是本文的主角 Azure Table storage. Azure Table storage 是一个在云端存储结构化 NoSQL 数据的服务,它不仅存取速度快,而且效费比高.MSDN 上的说法是:成本显著低于传统 SQL! 笔者最近在项目中用 Table storage 实现了一个日志表,在此和大家分享一下 Table stora

Azure Blob Storage 基本用法 -- Azure Storage 之 Blob

Azure Storage 是微软 Azure 云提供的云端存储解决方案,当前支持的存储类型有 Blob.Queue.File 和 Table. 笔者在<Azure Table storage 基本用法>一文中,介绍了 Table Storage 的基本用法,本文将通过 C# 代码介绍 Blob Storage 的主要使用方法. 文章来源:葡萄城产品技术社区 Blob Storage 是什么? Azure Blob Storage 是用来存放大量的像文本.图片.视频等非结构化数据的存储服务.我

Azure File Storage 基本用法 -- Azure Storage 之 File

Azure Storage 是微软 Azure 云提供的云端存储解决方案,当前支持的存储类型有 Blob.Queue.File 和 Table. 笔者在<Azure Blob Storage 基本用法>中介绍了 Blob Storage 的基本用法,本文将介绍 File Storage 的主要使用方法. File Storage 是什么? Azure File Storage 是一个通过 Server Message Block (SMB) 协议提供云端文件共享的服务.通过 File Stor

Windows Azure入门教学系列 (六):使用Table Storage

本文是Windows Azure入门教学的第六篇文章. 本文将会介绍如何使用Table Storage.Table Storage提供给我们一个云端的表格结构.我们可以把他想象为XML文件或者是一个轻量级的数据库(当然,不是通过SQL 语句进行数据的操作). 使用Table Storage的方法依然是调用REST API.有关Table Storage REST API的详细信息,请参见Table服务API: 为了方便.NET开发人员,我们在SDK中提供了Microsoft.WindowsAzu

利用AjAX动态变换过滤条件

ajax|动态|条件 在我的一个java项目中,需要在数据列表的上面添加过滤功能,可且根据用户选择的过滤条件,来生成不同过滤脚本://**********************以下是表格的第一行脚本***************************//   <TD align="center" width="15%" height="25">选择查询条件:</TD> <TD align="left&q

微软-Microsoft Azure table连接出错

问题描述 Microsoft Azure table连接出错 我要从table里面读数据,之前一直很好用 ,昨天突然读取不了数据了.是我的电脑少装了什么软件吗?sdk有问题?请知道的大神指导一下,谢谢了. 解决方案 Hi, 正如苏小喵所说,我们首先去检查下账号是否过期,网络连接是否正常,你也可以尝试使用Azure Storage Explorer这个工具去连接Azure存储中的Tables, 下载地址: https://azurestorageexplorer.codeplex.com/, 这个

SQL有外连接的时候注意过滤条件位置否则会导致网页慢_MsSql

奶奶的,为啥现在五一节只放3天,5月的天气最适合出游了,不过俺们这些苦逼的IT男是没法享受了. 一来到公司,项目经理就找到开发leader,说我们网站 页面很慢,让他排查原因. 一听说 网站慢,页面慢哥就来精神了,哥的老本行就是 解决"慢"的问题. 开发leader 很郁闷的说,我们已经加了 memcache了,20分钟 cache一次,咋个还是慢呢, 于是哥就问,那个网页跑了哪些SQL? 能抓出来让我看看吗? 开发Leader 果断的把SQL 抓了出来. 经过排查,我们发现了一个SQ

请问这个SQL的过滤条件是怎么执行的

问题描述 select e.ename,e.salary,e.deptnofrom employee e join (select deptno,round(avg(salary)) avgsal from employee group by deptno) aon e.deptno = a.deptnoand e.salary > a.avgsalfrom 后面的子句查询出的结果是三条,我想知道e.salary > a.avgsal这个过滤条件是只要大于a表中的一条记录就可以还是大于a表中的

求解:hibernate使用sql-query标签如何添加过滤条件.

问题描述 <sql-queryname="queryC"><![CDATA[SELECT{c.*}FROMCc,(SELECTcidASppFROMRWHERErid=?)bWHEREc.cic=b.pp]]><returnalias="c"class="test.C"/></sql-query>Queryquery=session.getNamedQuery("test.c.queryC