鉴于“包含”,我想知道此查询为何/如何在Azure存储表上运行 are not allowed in Azure Table Service? 这不是我想的那样吗?它正在运行并获取值。 另外,这是先获取整个表然后进行过滤吗?在调试器中,它看起来好像无法完全运行,直到我运行ToList()为止?
这是我的代码,我使用的底线是一个容器。
List<string> partitionIds = new List<string> {"1", "2", "3"};
var table = // get table here...
var result = table.ExecuteQuery(new TableQuery<ConnectionEntity>());
var queryResult = result.Where(w => partitionIds.Contains(w.PartitionKey)).ToList();
答案 0 :(得分:1)
如您提供的网站上所述,Azure Table服务不支持包含语句的验证。由于数据保存在无序列的环境中,所以contains语句可能需要大量的功能,具体取决于数据集的大小。此刻,您的查询向服务器发送了一个请求,请求整个数据集(result.GetAll())。在您的系统上,它评估服务器返回的数据集上的包含部分(result.where(contains).tolist())。这样,服务器不会评估您的contains语句,因此服务器很满意。但是,您的服务器仍需要做大量工作来评估此语句!
第二个问题:在Entity Framework中获取数据的标准方法是及时获取数据。这意味着,它仅在需要数据时(即当数据转换为列表时,尝试遍历或打印时)评估查询。尽早获得它的唯一方法是通过调用result.Load()而不是.toList()显式加载它。之后,您仍然可以调用.toList(),但是在显式声明.Load()的那一刻,结果集已加载。
答案 1 :(得分:1)
我知道这是一篇过时的文章,但是我们实际上遇到了类似的问题,但是我没有发现更新的内容。
加载所有数据并过滤它们不是我们的选择。另外,一个接一个地加载记录也是不可接受的解决方案。
因此,在查询中执行此操作最简单的方法是创建一个倍数或条件。将其更改为new TableQuery<ConnectionEntity>().Where(w => w.PartitionKey == "1" || w.PartitionKey == "2" || ...)
。
这项工作很好,但是当然有一些限制。通过我们的测试,我们得到了400个BadRequest,其中包含大约110个条件。
但是,如果您知道计数不是那么多,您可以这样做。
我写了一个扩展方法来像动态.Contains()
(在Microsoft.Azure.Cosmos.Table库中测试过)那样,在一个IQueryable上进行此操作,这并不容易:)
这是代码
/// <summary>
/// Convert Contains to a concatenated Or condition for Azure Table query support
/// </summary>
/// <typeparam name="T">Entity type</typeparam>
/// <typeparam name="TParam">property type to check</typeparam>
/// <param name="query">current query to extend</param>
/// <param name="values">Values to proof</param>
/// <param name="property">Which property should be proofed</param>
/// <returns></returns>
public static IQueryable<T> WhereContains<T, TParam>(this IQueryable<T> query, IEnumerable<TParam> values, Expression<Func<T, TParam>> property)
{
var enumerable = values.ToList();
if (!enumerable.Any())
return query;
Expression<Func<T, bool>> predicate = null;
var parameter = Expression.Parameter(typeof(T), "entity");
var propertyName = ((property.Body as MemberExpression)?.Member as PropertyInfo)?.Name
?? throw new Exception("Property can't be evaluated");
foreach (var value in enumerable)
{
var scope = new ExpressionScopedVariables { Value = value };
var filterStringExp = Expression.Constant(scope);
var getVariable = typeof(ExpressionScopedVariables).GetMember("Value")[0];
var access = Expression.MakeMemberAccess(filterStringExp, getVariable);
Expression<Func<T, bool>> currentExpression = Expression.Lambda<Func<T, bool>>(
Expression.Equal(
Expression.Property(parameter, propertyName),
access), parameter);
predicate = predicate == null ? currentExpression : Expression.Lambda<Func<T, bool>>(Expression.OrElse(predicate.Body, currentExpression.Body), predicate.Parameters);
}
return query.Where(predicate ?? throw new InvalidOperationException());
}
class ExpressionScopedVariables
{
// ReSharper disable once UnusedAutoPropertyAccessor.Local
public object Value { get; set; }
}
示例以及如何使用它
var query = from v in _baseRepository.AsQueryable()
where v.PartitionKey == partitionKey
select v;
query = query.WhereContains(entityIds, v => v.RowKey);
var entities = (await query.QueryAsync()).ToList();
_baseRepository
是我们自己的CloudTable存储库实现,而AsQueryable()
和QueryAsync()
是用于创建和执行查询的扩展方法