本文是在 《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 是本文的主角,它代表了某个表上的一个查询。基本用法是使用查询条件构建一个 TableQuery 类的实例,然后把这个实例作为参数传递给 CloudTable 的ExecuteQuery 方法:

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

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

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

此时函数的返回结果为: "(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 - ;
Char lastChar = startStr[endIndex];
// 找到比字符'c'大的那个字符。
Char afterLastChar = (char)(lastChar + );
// 拼出字符串 "abd"
string endStr = startStr.Substring(, 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, ""),
TableOperators.And,
"(RowKey ge 'abc') and (RowKey lt 'abd')"
);

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

(PartitionKey eq '') 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 - ;
Char lastChar = startsWithString[endIndex];
Char afterLastChar = (char)(lastChar + );
string endStr = startsWithString.Substring(, 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("", "");
List<MyLogEntity> result = myStartsWithQuery.Execute(logTable);

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

总结

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

Azure 基础:自定义 Table storage 查询条件的更多相关文章

  1. Azure 基础:Table storage

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

  2. Azure 基础:Blob Storage

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

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

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

  4. Azure 基础:Queue Storage

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

  5. Azure 基础:File Storage

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

  6. JEECG中datagrid方法自定义查询条件

    自定义加添加查询条件的用法: CriteriaQuery cq = new CriteriaQuery(EquipmentEntity.class, dataGrid); //查询条件组装器 org. ...

  7. Windows Azure Table Storage 解决 Guid 查询问题

    在使用 Windows Azure Table Storage 的 CloudTableClient 对Azure 进行数据查询时,会发现在自定义类的Guid类型始终无法去成功查询出数据,对比发现 G ...

  8. Azure Storage 系列(四)在.Net 上使用Table Storage

    一,引言 今天我们就不多说废话了,直接进入正题,Azure Table Storage.开始内容之前,我们先介绍一下Azure Table Storage. 1,什么是Azure Table Stor ...

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

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

随机推荐

  1. C# 倒计时

    c#中有一个叫做timespan的数据类型,可以这样构造: TimeSpan ts = , , ); TimeSpan(hour,minute,second); 然后拖进去一个timer,叫timer ...

  2. 转:Newtonsoft.Json高级用法

    原文地址:http://www.cnblogs.com/yanweidie/p/4605212.html 手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口多 ...

  3. 《SQL Server 2008从入门到精通》--20180716

    1.锁 当多个用户同时对同一个数据进行修改时会产生并发问题,使用事务就可以解决这个问题.但是为了防止其他用户修改另一个还没完成的事务中的数据,就需要在事务中用到锁. SQL Server 2008提供 ...

  4. It was not possible to find any compatible framework version

    It was not possible to find any compatible framework version The specified framework 'Microsoft.NETC ...

  5. PowerShell “execution of scripts is disabled on this system.”

    Set-ExecutionPolicy RemoteSigned

  6. leetcode 486 预测赢家

    题目描述 给定一个表示分数的非负整数数组. 玩家1从数组任意一端拿取一个分数,随后玩家2继续从剩余数组任意一端拿取分数,然后玩家1拿,--.每次一个玩家只能拿取一个分数,分数被拿取之后不再可取.直到没 ...

  7. 以太坊预言机与WEB API(原创,转载请说明原址)

    什么是预言机? 从链外获得数据,提供区块链与现实世界事件之间的连接,提供外部信息的平台 预言机自身也是一种智能合约,它允许区块链连接到任何现有的API 是这个预言机去调用各种 WEB API的接口 这 ...

  8. 实现统计 android手机 CPU使用率

    # -*- coding:utf-8 -*- ''' Created on Sep 10, 2018 @author: SaShuangYiBing ''' import subprocess imp ...

  9. Linux解压.tar .tgz .tar.gz .tar.Z等文件

    .tar 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName (注:tar是打包,不是压缩!) ---------------------- ...

  10. pyspider中内容选择器常用方法汇总

    pyspider 的内容选择器默认已经实例化一个pyquery对象,可以直接使用pyquery的api来获取自己需要的内容. 1.在pyquery中使用response.doc就可以直接实例化一个py ...