当从"WindowsAzure.Storage"迁移到Azure Tables时,我应该使用哪个包?

8
我目前正在将一个使用ASP.NET WebApi编写的.NET Fx 4.8项目迁移到.NET 5.0。该项目大量使用WindowsAzure.Storage包以访问Azure存储帐户上的BLOB、表和队列。该包已经被弃用了一段时间,说明已将其拆分为几个包。
对于队列和Blobs来说,我应该迁移到什么已经很明显了。但是有关Azure Tables,似乎存在很多混淆。
  • 首先,在NuGet包WindowsAzure.Storage中指出,应使用Microsoft.Azure.CosmosDB.Table包来处理table。这有点令人困惑,因为我一直认为"CosmosDB"与"Azure Tables"完全不同,但也许我错了。
  • Microsoft.Azure.CosmosDB.Table的描述说明,该包处于维护模式并将被弃用。应改用Microsoft.Azure.Cosmos.Table代替。
  • Microsoft.Azure.Cosmos.Table已经很久没有更新了,2.0.0预览版已经超过两年了。它的GitHub存储库中还有一个问题,专门询问这个项目是否已死 - 没有答案。
  • 在搜索后,我发现Azure.Data.Tables包最接近我可能正在寻找的内容。它被更新了,看起来仍在维护,与其他存储包版本号相符。只是命名有点不同。今年6月,MS还发布了一篇博客文章,介绍了这个全新的包,所以我想这就是我要找的东西?
无论如何:我发现Azure.Data.Tables的API与WindowsAzure.Storage非常相似,我只需要做一些微调。
但我现在完全缺少QueryComparisonsTableQuery类。它们消失了吗?有替代品吗?

需要迁移的代码示例:

var part1 = 
  TableQuery.GenerateFilterConditionForGuid(
    nameof(SomeEntity.Id),
    QueryComparisons.Equal,
    idValue));
var part2 = 
  TableQuery.GenerateFilterConditionForGuid(
    nameof(SomeEntity.Category)
    QueryComparisons.Equal,
    category));
return TableQuery.CombineFilters(part1, TableOperators.And, part2);

请编辑您的问题并包含您希望迁移的当前代码。 - Gaurav Mantri
请注意,Cosmos.Table于2020年进行了更新,最新版本为1.0.8。此版本包含了您的类。但是,请注意预览版是在2019年更新的。https://www.nuget.org/packages/Microsoft.Azure.Cosmos.Table/1.0.8 - misha130
你最终解决了这个问题吗? - Josh
1
我最终使用了Azure.Data.Tables - Hemisphera
@Hemisphera 你如何找到替换类? - LakShan
就我所需的而言,新的API基本上是不言自明的。大多数类具有相同的名称。我只是偶尔会错过一些常量(如Query、Comparison)。但由于时间不足,我只好反编译“旧”库并复制他们在那里所做的事情。 - Hemisphera
4个回答

4

我遇到了同样的问题。是的,来自 Microsoft.Azure.Cosmos.TablesTableQuery 已经不存在了,并且文档中对 TableOdataFilter 的引用是无用的,因为它已经不存在了。

看到这些,我发现使用 Azure.Data.Tables 包最简单的方式来查询 Azure 存储表是使用 .Query<T>([predicate]) 方法。例如:

TableClient customers;

var example = customers.Query<Customer>(c => c.Name == "Microsoft");

还有一个异步版本的.QueryAsync<T>(..)

如果您使用TableQuery构建查询,那么没有直接的替代方法,但是您可以使用类似PredicateBuilder的工具来组合.And().Or()表达式来创建谓词。

我修改了这个工具以创建流畅的版本:

    /// <summary>
    /// Helper class to build predicates fluently
    /// </summary>
    /// <remarks>
    /// Adapted from source: http://www.albahari.com/nutshell/predicatebuilder.aspx
    /// </remarks>
    public class PredicateBuilder<T>
    {
        private Expression<Func<T, bool>> expression;

        /// <summary>
        /// Add an OR clause
        /// </summary>
        /// <param name="expr">new expression</param>
        /// <returns></returns>
        public PredicateBuilder<T> Or(Expression<Func<T, bool>> expr)
        {
            if (expression == null)
                expression = expr;
            else
            {
                var invokedExpr = Expression.Invoke(expr, expression.Parameters.Cast<Expression>());
                expression = Expression.Lambda<Func<T, bool>>(Expression.OrElse(expression.Body, invokedExpr), expression.Parameters);
            }
            return this;
        }

        /// <summary>
        /// Add an AND clause
        /// </summary>
        /// <param name="expr">new expression</param>
        /// <returns></returns>
        public PredicateBuilder<T> And(Expression<Func<T, bool>> expr)
        {
            if (expression is null)
                expression = expr;
            else
            {
                var invokedExpr = Expression.Invoke(expr, expression.Parameters.Cast<Expression>());
                expression = Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expression.Body, invokedExpr), expression.Parameters);
            }
            return this;
        }

        /// <summary>
        /// Return resulting expression
        /// </summary>
        /// <returns></returns>
        public Expression<Func<T, bool>> ToPredicate()
        {
            if (expression is null)
                return (T value) => true;
            return expression;
        }
    }

示例用法:

var query = new PredicateBuilder<Customer>();

if(name != null)
  query.And(c => c.Name == name);

if (isActive == false)
  query.And(c => c.IsActive == false);

希望这能帮到你。

1
你可以使用OData语法或者LINQ语法与TableClient的Query方法一起使用。
以下是一个使用CreateQueryFilter助手的示例。
var queryResultsFilter2 = tableClient.Query<TableEntity>(filter: TableClient.CreateQueryFilter($"PartitionKey eq {partitionKey}"));
// Iterate the <see cref="Pageable"> to access all queried entities.
foreach (TableEntity qEntity in queryResultsFilter2)
{
    Console.WriteLine($"{qEntity.GetString("Product")}: {qEntity.GetDouble("Price")}");
}

Console.WriteLine($"The query returned {queryResultsFilter.Count()} entities.");

附注:如果您要与时间戳列进行比较,请确保将您的值转换为UTC格式,即。
 var filter = TableClient.CreateQueryFilter($"age ge 21 and Timestamp gt {DateTimeOffset.Now.AddDays(-3).ToUniversalTime()} ");

来源


0
我对Azure Package团队再次废弃我的奶酪并在过程中改变配方感到相当沮丧。经过一些挫折后,我发现通过应用简单的Linq查询语法可以满足基本使用案例。
这对我的需求起作用了。
var tableClient = await GetTableClientAsync("tableStorageKey");
var query = tableClient.Query<LogEntry>(x => x.PartitionKey == "myPartitionKey" && x.EntityType == "Product");

注意:查询不是非常强大,因此传入一个.Contains()条件将使查询失败。您需要在初始结果之后实现一个后查询来处理额外的数组参数。
productIds = new string[] { "123456", "234567" };
var tableClient = await GetTableClientAsync("tableStorageKey");
var query = tableClient.Query<ProductLogEntry>(x => x.PartitionKey == "myPartitionKey" && x.EntityType == "Product");
var result = query.Where(x => productIds.Contains(x.ProductId));

-1

你可能应该再仔细阅读一下那篇博客文章相关文档

查询表实体

TableClient允许用户使用OData过滤器创建自定义查询。

string MyPK = "markers";
string MyRK = "id-001";
string filter = TableOdataFilter.Create($"PartitionKey eq {MyPK} or RowKey eq {MyRK}")

Pageable<TableEntity> entities = tableClient.Query<TableEntity>(filter: filter);

foreach (TableEntity entity in entities)
{
    Console.WriteLine($"{entity.GetString("Product")}: {entity.GetInteger("Count")}");
}

1
TableOdataFilter 现在是一个内部类,因此不可用,因此应该小心处理文章内容。它也不完全是替代品:eqorand 等均被明确指定。组合查询未得到解释。 - Hemisphera
迁移到这个Azure存储/表版本真是一场噩梦... - jjxtra
令我惊讶的是,那篇博客文章仍然存在,提到了一个现在已隐藏的类,评论被锁定,没有指向最新文档的指针。 - Kit
@Kit Yeah - Azure软件包的文档可以说是一团糟。当你尝试对它们进行单元测试时,情况会变得更好,因为Azure软件包团队在他们无限的智慧中决定不为他们的软件包提供接口...这意味着这些软件包无法被模拟... - Ian Kemp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接