C# 如何在Azure表存储中使用整数行键?
我有连续编号的实体,我想在Azure表服务中保留这些实体,但是RowKey列的类型有问题。 实体的编号应该存储在RowKey列中,这样我可以快速查询实体(C# 如何在Azure表存储中使用整数行键?,c#,azure,azure-storage,C#,Azure,Azure Storage,我有连续编号的实体,我想在Azure表服务中保留这些实体,但是RowKey列的类型有问题。 实体的编号应该存储在RowKey列中,这样我可以快速查询实体(PK='..'&&RowKey=5),获取最新的实体(RowKey>10),并查询特定的实体集(RowKey>5&&RowKeye.ID>1&&e.ID
PK='..'&&RowKey=5
),获取最新的实体(RowKey>10
),并查询特定的实体集(RowKey>5&&RowKey<10
)
由于RowKey必须是字符串,低于比较值是有问题的(“100”<“11”
)。
我考虑过在数字前加上零(因此“100”>“011”
),但我无法预测实体的数量(因此也无法预测零的数量)
我知道我可以创建一个整数列,但是我会失去索引RowKey列的性能优势(另外,我没有任何其他适合RowKey的信息)。
以前有人遇到过这个问题吗?您可以将guid后附加到整数。这应该有助于分类。
我通过创建一个自定义的
RowKey
类解决了这个问题,该类围绕一个字符串,并提供一个增量
方法
我现在可以定义有效字符的范围(例如0-9+a-z+a-z
)和该范围内的“计数”(例如az9+1=aza
,azZ+1=aA0
)。与仅使用数字相比,这种方法的优点是,我有更大范围的可能键(62^n
,而不是10^n
)
我仍然需要预先定义字符串的长度,不能更改它,但现在我可以存储几乎任意数量的实体,同时保持字符串本身更短。例如,我可以用10位数字存储~8*10^17
键,用20位数字存储~7*10^35
当然,可以进一步增加有效字符的数量,以便更有效地使用位数,但在我的例子中,上述范围已经足够,并且仍然足够可读,以便进行调试
我希望这个答案能帮助其他遇到同样问题的人
编辑:作为旁注,以防任何人想要实现类似的功能:您必须创建自定义字符范围,并且不能从0开始向上计数,因为数字(
0-9
)之间存在非法字符(例如/
,\
)和小写字母。如果您使用
您将这样的内容添加到表格的模型中
public int ID
{
get
{
return int.Parse(RowKey);
}
}
然后您可以在Linq查询中执行此操作
.Where(e => e.ID > 1 && e.ID < 10);
,其中(e=>e.ID>1&&e.ID<10);
使用这种技术,您实际上并没有向表中添加“ID”列,因为它没有“set”操作
我唯一不确定的是幕后到底发生了什么。我想知道Azure表存储查询的最终形式是什么样的,但我不确定如何找到答案。在调试和使用quickwatch时,我无法找到这些信息
更新
我还没有弄清楚到底发生了什么,但我有一种强烈的感觉,这不是很有效。我在想,要做的就是像OP一样创建一个。然后可以在Linq where子句中使用
RowKey.CompareTo()
函数按范围进行筛选 我找到了一个简单的方法,但是前面的解决方案更有效(关于密钥长度)。
我们不需要使用所有字母表,只需要使用数字,关键是使长度固定(0000000 10002,…):
公共类可读性:TableEntity
{
公共静态字符串KeyLength=“000000000000000”;
公共可读性(字符串分区ID,int-keyId)
{
this.PartitionKey=partitionId;
this.RowKey=keyId.ToString(KeyLength);
}
公众可读性()
{
}
}
公共IList Get(字符串partitionName、int-date、int-enddate)
{
CloudTableClient tableClient=storageAccount.CreateCloudTableClient();
//创建表示“人员”表的CloudTable对象。
CloudTable=tableClient.GetTableReference(“记录”);
//为所有客户实体构造查询操作,其中PartitionKey=“Smith”。
TableQuery=new TableQuery()。其中(TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition(“PartitionKey”,QueryComparisons.Equal,partitionName),
TableOperators.And,TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition(“RowKey”、QueryComparisons.LessThan、enddate.ToString(ReadingEntity.KeyLength))、TableOperators和,
TableQuery.GenerateFilterCondition(“RowKey”,QueryComparisons.GreaterThanOrEqual,date.ToString(ReadingEntity.KeyLength'));
return table.ExecuteQuery.ToList();
}
希望这能有所帮助。我也遇到了类似的问题,还有一个额外的警告,我还希望支持按降序排序行键。在我的例子中,我并不关心支持数以万亿计的可能值,因为我正确地使用了PartitionKey,并且在需要进一步分段RowKey时也使用了作用域前缀(如“scope id”->“12-8374”) 最后,我决定具体实施恩齐建议的一般方法。我使用了Base64编码的修改版本,生成了一个四个字符的字符串,它支持1600多万个值,可以按升序或降序排序。下面是代码,它已经过单元测试,但缺少范围检查/验证
//
///获取指定整数id的四个字符串表示形式。
///
///要转换的数字
///指示编码的数字将按升序还是降序排序
///数字的编码字符串表示形式
公共静态字符串NumberToId(整数,布尔升序=true)
{
如果(!升序)
编号=16777215-编号;
返回新字符串(新[]{
六位字符((字节)((数字
public class ReadingEntity : TableEntity
{
public static string KeyLength = "000000000000000000000";
public ReadingEntity(string partitionId, int keyId)
{
this.PartitionKey = partitionId;
this.RowKey = keyId.ToString(KeyLength); ;
}
public ReadingEntity()
{
}
}
public IList<ReadingEntity> Get(string partitionName,int date,int enddate)
{
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Create the CloudTable object that represents the "people" table.
CloudTable table = tableClient.GetTableReference("Record");
// Construct the query operation for all customer entities where PartitionKey="Smith".
TableQuery<ReadingEntity> query = new TableQuery<ReadingEntity>().Where(TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionName),
TableOperators.And,TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThan, enddate.ToString(ReadingEntity.KeyLength)), TableOperators.And,
TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.GreaterThanOrEqual, date.ToString(ReadingEntity.KeyLength)))));
return table.ExecuteQuery(query).ToList();
}