7

我在我的应用程序中经常出现这样的情况,我创建了一个查询来获取 partitionkey 是常量但 rowkey 应该在词法范围内的所有实体(例如,只有以某个前缀开头的行):

//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();

我必须使用 CompareTo,因为此类查询不支持 StartsWith 等字符串函数。这行得通,但是条件很难阅读并且重复了很多次。因此,与其使用这种难以阅读的条件编写大量查询,我更愿意创建一个“内联”它的函数:

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();

但是当我运行它时,我从 Azure 收到一个关于我的功能不受支持的异常。有没有办法写这个以便支持它?毕竟,我使用的条件与有效的查询完全相同,只是包装在一个函数中......

4

2 回答 2

17

这是凯文答案的概括。它做同样的事情,但适用于任何前缀字符串,而不仅仅是大卫在原始问题中询问的特定情况。

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;
}
于 2012-10-23T17:56:14.857 回答
10

如果将条件分解为函数,则函数需要返回表达式树而不是布尔值。我不知道 LINQ 查询语法是否支持这一点,但您可以使用方法语法如下:

public static Expression<Func<MyEntity, bool>> HasPrefix(String prefix) 
{ 
    return e => e.RowKey.CompareTo(prefix + '_') > 0 && e.RowKey.CompareTo(prefix + '`') <= 0;
}

CloudTableQuery<MyEntity> query =
    (from e in tableServiceContext.CreateQuery<MyEntity>(tableName)
    where e.PartitionKey == "KnownPartition"
    select e)
    .Where(HasPrefix("Prefix"))
    .AsTableServiceQuery();
于 2012-10-18T17:52:48.877 回答