Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure table storage range query with commonly used condition wrapped in method

I have a common occurence in my application where I create a query to get all entities where partitionkey is constant but rowkey should be within an lexical range (e.g. only rows which start with some prefix):

//query to get all entities in partition "KnownPartition" where RowKey starts with "Prefix_"
CloudTableQuery<MyEntity> query =
    (from e in tableServiceContext.CreateQuery<MyEntity>(tableName)
     where e.PartitionKey == "KnownPartition"
           && e.RowKey.CompareTo("Prefix_") > 0
           && e.RowKey.CompareTo("Prefix`") <= 0 // ` is '_' + 1
     select e).AsTableServiceQuery();

I must use CompareTo because string functions such as StartsWith are not supported in this kind of query. This works, but the condition is hard to read and repeated a lot. So instead of writing a lot of queries with this hard-to-read condition, I'd rather like to make a function which "inlined" it:

public static Boolean HasPrefix(this String rowKey, String prefix)
{
    return rowKey.CompareTo(prefix + '_') > 0 && rowKey.CompareTo(prefix + '`') <= 0;
}

CloudTableQuery<MyEntity> query =
    (from e in tableServiceContext.CreateQuery<MyEntity>(tableName)
     where e.PartitionKey == "KnownPartition" && e.RowKey.HasPrefix("Prefix")
     select e).AsTableServiceQuery();

But when I run this, I get an exception from Azure about my function not being supported. Is there any way to write this so that it is supported? After all, I'm using the exact same condition as the query that worked, just wrapped in a function...

like image 943
David S. Avatar asked Oct 18 '12 16:10

David S.


1 Answers

Here is a generalization of Kevin's answer. It does the same thing, but works for any prefix string rather than just the specific case David asked about in the original question.

public static Expression<Func<MyEntity, bool>> HasPrefix(String prefix) 
{ 
    char lastChar = prefix[prefix.Length - 1];
    char nextLastChar = (char)((int)lastChar + 1);
    string nextPrefix = prefix.Substring(0, prefix.Length - 1) + nextLastChar;

    return e => e.RowKey.CompareTo(prefix) >= 0 && e.RowKey.CompareTo(nextPrefix) < 0;
}
like image 91
Brian Reischl Avatar answered Oct 06 '22 01:10

Brian Reischl