I know it's an old post, but we have actual a similar problem and I didn't found something newer.
To load all data and filter them was not an option for us. Also to load the record one by one is not an acceptable solution.
So the easiest way to do it within a query is to create an multiple or conditions. To change it to something like new TableQuery<ConnectionEntity>().Where(w => w.PartitionKey == "1" || w.PartitionKey == "2" || ...)
.
This work's well but it has of course some limitations. With our tests we got 400 BadRequest with more then about 110 conditions.
But for if you know, the count is not that much, you can do this.
I wrote an extension method to do this on an IQueryable dynamicly like .Contains()
(tested with Microsoft.Azure.Cosmos.Table library) It wasn't easy :)
Here is the code
/// <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; }
}
And the example how to use it
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
is our own CloudTable repository implementation and AsQueryable()
and QueryAsync()
are extension methods to create and to execute the query