2

我正在使用 azure 表存储来存储博客文章。每篇博文都可以有不同的标签。所以我将有三个不同的表。

  • 一个将存储博客文章。
  • 一个用于存储标签
  • 一种将存储标签和帖子之间的关系

所以我的问题如下,是否可以创建动态搜索查询?因为直到运行时我才知道要搜索多少个标签。据我了解,您只能使用 LINQ 查询天蓝色表。或者我可以输入一个可以动态更改的字符串查询吗?

更新

这是博客表中的一些示例数据

PartitionKey,RowKey,Timestamp,Content,FromUser,Tags
user1, 1, 2012-08-08 13:57:23, "Hello World", "root", "yellow,red"

博客标签表

PartitionKey,RowKey,Timestamp,TagId,TagName
"red", "red", 2012-08-08 11:40:29, 1, red
"yellow", "yellow", 2012-08-08 11:40:29, 2, yellow

关系表

PartitionKey,RowKey,Timestamp,DataId,TagId
1, 1, 2012-08-08 11:40:29, 1, 1
2, 1, 2012-08-08 13:57:23, 1, 2

这些表的一个使用示例是,例如,当我想获取所有带有特定标签的博客文章时。

  • 我必须从 blogTag 表中查询 tagId
  • 在我需要在关系表中搜索 dataId 之后
  • 最后,我需要在博客表中搜索具有该 dataId 的博客文章

我正在使用 LINQ 执行查询,它看起来像以下

CloudTableQuery<DataTag> tagIds = (from e in ctx2.CreateQuery<DataTag>("datatags")
                                   where e.PartitionKey == tags
                                   select e).AsTableServiceQuery<DataTag>();

我尝试了使用过滤器的 Gaurav Mantri 建议,它有效。但我担心这样做的效率会如何。关于仅允许进行 15 次离散比较的限制。

4

4 回答 4

2

您可以简单地构建where 子句并传递给 where 方法,例如:

var whereClause="(PartitionKey eq 'Key1') and (PartitionKey eq 'Key2')"

CloudStorageAccount storageAccount = CloudStorageAccount.Parse("AccountDetails");
            CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

            CloudTable table = tableClient.GetTableReference(<TableName>);
            table.CreateIfNotExists();

            TableQuery<YourAzureTableEntity> query =
               new TableQuery<YourAzureTableEntity>()
                  .Where(whereClause));
            var list = table.ExecuteQuery(query).ToList();
于 2014-04-30T08:14:03.343 回答
1

我也面临完全相同的问题。我确实找到了一个我在下面粘贴的解决方案:

public static IEnumerable<T> Get(CloudStorageAccount storageAccount, string tableName, string filter)
    {
        string tableEndpoint = storageAccount.TableEndpoint.AbsoluteUri;
        var tableServiceContext = new TableServiceContext(tableEndpoint, storageAccount.Credentials);
        string query = string.Format("{0}{1}()?filter={2}", tableEndpoint, tableName, filter);
        var queryResponse = tableServiceContext.Execute<T>(new Uri(query)) as QueryOperationResponse<T>;
        return queryResponse.ToList();
    }

基本上它利用 DataServiceContext 的 Execute(Uri) 方法:http: //msdn.microsoft.com/en-us/library/cc646700.aspx

您需要像通过 REST API 调用查询功能一样指定过滤条件(例如 PartitionKey eq 'mypk' 和 RowKey ge 'myrk')。不确定这是否是最好的解决方案:) 期待对此发表评论。

于 2012-08-09T13:54:24.687 回答
0

在表存储中构建这样的东西非常麻烦;类似于将方形钉钉在圆孔中。

相反,您可以考虑使用 Blob 存储来存储您的博客和 Lucene.NET 来实现您的标签搜索。Lucene 还允许更复杂的搜索,例如 (Tag = "A" and Tag = "B" and Tag != "C"),此外还允许搜索博客文本本身,如果您愿意的话。

http://code.msdn.microsoft.com/windowsazure/Azure-Library-for-83562538

于 2012-08-09T16:01:41.353 回答
0

这是可能的,但这可能不是一个好主意。像这样添加多个查询参数总是会导致表扫描。这在一张小桌子上可能没问题,但如果你的桌子很大,它会很慢。对于大型表,您最好为每个组合键运行单独的查询。

也就是说,您可以使用一些 LINQ 魔法构建动态查询。这是我为此使用的辅助类:

public class LinqBuilder
{
    /// <summary>
    /// Build a LINQ Expression that roughly matches the SQL IN() operator
    /// </summary>
    /// <param name="columnValues">The values to filter for</param>
    /// <returns>An expression that can be passed to the LINQ  .Where() method</returns>
    public static Expression<Func<RowType, bool>> BuildListFilter<RowType, ColumnType>(string filterColumnName, IEnumerable<ColumnType> columnValues)
    {
        ParameterExpression rowParam = Expression.Parameter(typeof(RowType), "r");
        MemberExpression column = Expression.Property(rowParam, filterColumnName);

        BinaryExpression filter = null;
        foreach (ColumnType columnValue in columnValues)
        {
            BinaryExpression newFilterClause = Expression.Equal(column, Expression.Constant(columnValue));
            if (filter != null)
            {
                filter = Expression.Or(filter, newFilterClause);
            }
            else
            {
                filter = newFilterClause;
            }
        }

        return Expression.Lambda<Func<RowType, bool>>(filter, rowParam);
    }

    public static Expression<Func<RowType, bool>> BuildComparisonFilter<RowType, ColumnType>(string filterColumnName, Func<MemberExpression, BinaryExpression> buildComparison)
    {
        ParameterExpression rowParam = Expression.Parameter(typeof(RowType), "r");
        MemberExpression column = Expression.Property(rowParam, filterColumnName);

        BinaryExpression filter = buildComparison(column);
        return Expression.Lambda<Func<RowType, bool>>(filter, rowParam);
    }

}

你会像这样使用它:

var whereClause = BuildListFilter(queryColumnName, columnValues);
CloudTableQuery<RowType> query = (from r in tableServiceContext.CreateQuery<MyRow>("MyTable")
                                    where r.PartitionKey == partitionKey
                                    select r)
                                    .Where(whereClause) //Add in our multiple where clauses
                                    .AsTableServiceQuery(); //Convert to table service query
var results = query.ToList();

另请注意,表服务对每个查询强制执行最大数量的约束。记录的最大值是每个查询 15,但是当我最后一次尝试这个时(这是一段时间前),实际最大值是 14。

于 2012-08-09T14:58:30.543 回答