Saturday, January 16, 2016

Azure Table Combined Conditions

If you have multiple conditions that must be combined to build a complete Azure Table query, the code can get verbose, increasingly so if there are 3 or more conditions. Extra complexity arises if not all of the conditions are needed. You might finish up with a cluttered mess of code that uses GenerateFilterCondition and CombineFilter methods sprinkled with if statements. The CombineFilter method only takes two arguments, so to combine more conditions you have to nest calls to it.

A LINQ Aggregate trick can be used to simplify building query strings. Here is a sample that has four imaginary conditions which must be combined if the argument to each one is not null.

public string BuildWhere(string pk, string rk, string user, int? rating)
{
  var conditions = new string[]
  {
    pk == null ? null : TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, pk),
    rk == null ? null : TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, rk),
    user == null ? null : TableQuery.GenerateFilterCondition("User", QueryComparisons.Equal, user),
    rating == null ? null : TableQuery.GenerateFilterConditionForInt("Rating", QueryComparisons.Equal, rating.Value)
    // There may be more conditions...
  }
  return conditions
      .Where(c => c != null)
      .DefaultIfEmpty()
      .Aggregate((a, b) => TableQuery.CombineFilters(a, TableOperators.And, b));
}

1. Build a string array of all possible conditions, leaving null entries for those not needed. The GenerateFilterXXX methods safely generate strings with the correct syntax required by Azure Table queries.

2. Run LINQ Aggregate over the conditions to multi-nest the non-null ones inside CombineFilter calls. The sample code works correctly no matter how many conditions are non-null, even one or zero. The resulting string has this structure:

Combine(Combine(Combine(pk,rk),user),rating)

The Aggregate processing creates a effect similar to the way Mathematica's Nest function works. It's a neat and elegant example of the power of LINQ and functional programming style.

P.S. The CombineFilters in my sample is just a fancy and verbose way of putting the word 'and' between two string conditions. Knowing this, the technically correct Aggregate code above can be simplified to this:

return string.Join(" and ", conditions.Where(c => c != null));

No comments:

Post a Comment