运行 Azure 中包含运算符 Table 服务 linq 查询
Running a Contains operator in Azure Table Service linq query
我想知道 why/how 此查询 运行 在 Azure 存储 table 上执行,因为 'contains'
are not allowed in Azure Table Service?
这不是在做我认为它在做的事情吗?它正在 运行 宁和获取值。
另外,这是先获取整个 table 然后过滤吗?在调试器中,它似乎没有 运行 完全,直到我 运行 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();
如您提供的网站所述,Azure Table 服务不支持包含语句的验证。由于数据保存在 no-SQL 环境中,contains 语句可能需要大量的能量,具体取决于数据集的大小。目前,您的查询向服务器发送请求,请求整个数据集 (result.GetAll() )。在您的系统上,它评估服务器返回的数据集的包含部分 (result.where(contains).tolist() )。这样,服务器就不会评估您的 contains 语句,因此服务器会感到满意。但是,您的服务器仍然需要做很多工作来评估此语句!
关于您的第二个问题:在 Entity Framework 中获取数据的标准方法是及时获取。这意味着,它只在需要数据的时候评估查询,也就是数据被转换为列表的时候,当你试图遍历它,或者当你试图打印它的时候。更早获取它的唯一方法是通过调用 result.Load() 而不是 .toList() 显式加载它。之后,你仍然可以调用.toList(),但是结果集是在你明确声明.Load()的那一刻加载的。
我知道这是一个旧的 post,但我们确实遇到了类似的问题,但我没有找到更新的东西。
加载所有数据并过滤它们对我们来说不是一个选项。同样,一条一条地加载记录也不是一个可以接受的解决方案。
因此,在查询中执行此操作的最简单方法是创建多个或条件。将其更改为 new TableQuery<ConnectionEntity>().Where(w => w.PartitionKey == "1" || w.PartitionKey == "2" || ...)
.
这项工作很好,但当然也有一些局限性。通过我们的测试,我们得到了 400 个包含超过 110 个条件的 BadRequest。
但是如果你知道的话,数量不是那么多,你可以这样做。
我写了一个扩展方法来动态地在 IQueryable 上执行此操作,例如 .Contains()
(使用 Microsoft.Azure.Cosmos.Table 库测试)这并不容易 :)
这是代码
/// <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()
是创建和执行查询的扩展方法
我想知道 why/how 此查询 运行 在 Azure 存储 table 上执行,因为 'contains' are not allowed in Azure Table Service? 这不是在做我认为它在做的事情吗?它正在 运行 宁和获取值。 另外,这是先获取整个 table 然后过滤吗?在调试器中,它似乎没有 运行 完全,直到我 运行 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();
如您提供的网站所述,Azure Table 服务不支持包含语句的验证。由于数据保存在 no-SQL 环境中,contains 语句可能需要大量的能量,具体取决于数据集的大小。目前,您的查询向服务器发送请求,请求整个数据集 (result.GetAll() )。在您的系统上,它评估服务器返回的数据集的包含部分 (result.where(contains).tolist() )。这样,服务器就不会评估您的 contains 语句,因此服务器会感到满意。但是,您的服务器仍然需要做很多工作来评估此语句!
关于您的第二个问题:在 Entity Framework 中获取数据的标准方法是及时获取。这意味着,它只在需要数据的时候评估查询,也就是数据被转换为列表的时候,当你试图遍历它,或者当你试图打印它的时候。更早获取它的唯一方法是通过调用 result.Load() 而不是 .toList() 显式加载它。之后,你仍然可以调用.toList(),但是结果集是在你明确声明.Load()的那一刻加载的。
我知道这是一个旧的 post,但我们确实遇到了类似的问题,但我没有找到更新的东西。
加载所有数据并过滤它们对我们来说不是一个选项。同样,一条一条地加载记录也不是一个可以接受的解决方案。
因此,在查询中执行此操作的最简单方法是创建多个或条件。将其更改为 new TableQuery<ConnectionEntity>().Where(w => w.PartitionKey == "1" || w.PartitionKey == "2" || ...)
.
这项工作很好,但当然也有一些局限性。通过我们的测试,我们得到了 400 个包含超过 110 个条件的 BadRequest。
但是如果你知道的话,数量不是那么多,你可以这样做。
我写了一个扩展方法来动态地在 IQueryable 上执行此操作,例如 .Contains()
(使用 Microsoft.Azure.Cosmos.Table 库测试)这并不容易 :)
这是代码
/// <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()
是创建和执行查询的扩展方法