Как запросить хранилище таблиц azure с помощью одинарной кавычки в PartitionKey


Я переношу некоторый код из старого клиента хранилища таблиц azure в последнюю версию и столкнулся с проблемой, которая поставила меня в тупик: я не могу отправить запрос с одной кавычкой в ключе раздела, не получив 400 неверных запросов. Например:

public class TestEntity : TableEntity
{
    public string TestProperty { get; set; }
}

public class StorageTester
{
    public static void TestInsert()
    {
        CloudStorageAccount acct = CloudStorageAccount.DevelopmentStorageAccount;
        CloudTableClient client = acct.CreateCloudTableClient();
        CloudTable table = client.GetTableReference("testtable");
        table.CreateIfNotExists();

        // insert a test entity -- this works fine
        TestEntity entity = new TestEntity();
        entity.PartitionKey = "what's up";
        entity.RowKey = "blah";
        entity.TestProperty = "some dataz";

        TableOperation op = TableOperation.Insert(entity);
        table.Execute(op);

        // now query the entity -- explicit query constructed for clarity
        string partitionFilter = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "what's up");
        string rowFilter = TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, "blah");
        string finalFilter = TableQuery.CombineFilters(partitionFilter, TableOperators.And, rowFilter);

        TableQuery<TestEntity> query = new TableQuery<TestEntity>().Where(finalFilter);

        // THIS THROWS 400 ERROR, does not properly encode partition key
        var entities = table.ExecuteQuery(query, new TableRequestOptions { RetryPolicy = new NoRetry() });
        entity = entities.FirstOrDefault();

    }
}

Я перепробовал все... Я попытался явно задать свойство FilterString в Tabletquery, но оно выполняет кодировку URL после установки этого свойства, поэтому если я заменю одиночную кавычку на %27, то % получит дважды сбежал.

Есть ли у кого-нибудь обходной путь, который позволил бы мне использовать новую библиотеку хранения таблиц, не возвращаясь к старой библиотеке StorageClient? Обратите внимание, что у меня уже есть много данных в существующей базе данных, поэтому такие решения, как "просто не используйте одиночные кавычки в запросах", были бы абсолютным крайним средством, поскольку это потребовало бы сканирования и обновления каждой отдельной записи в каждой существующей таблице-задача обслуживания, которую я хотел бы избежать.

2 8

2 ответа:

Вам нужно экранировать одинарную кавычку, но только при фильтрации (путем добавления одинарной кавычки перед исходной одинарной кавычкой):

string partitionFilter = TableQuery.GenerateFilterCondition("PartitionKey", 
          QueryComparisons.Equal, "what''s up");

Это происходит потому, что GenerateFilterCondition и CombineFilters превращают фильтр в простую строку (формат OData):

(PartitionKey eq 'what''s up') and (RowKey eq 'blah')

Более безопасным способом использования фильтров было бы следующее:

string partitionFilter = TableQuery.GenerateFilterCondition("PartitionKey", 
          QueryComparisons.Equal, partitionKey.Replace("'", "''"));

Я использую хранилище Windows Azure 7.0.0, и вы можете использовать запрос Linq, чтобы вам не нужно было экранировать одинарные кавычки:

// Get the cloudtable ...
var table = GetCloudTable();

// Create a query: in this example I use the DynamicTableEntity class
var query = cloudTable.CreateQuery<TestEntity>()
    .Where(d => d.PartitionKey == "what's up" && d.RowKey == "blah");

var entities = query.ToList();

Если вы проверите свойство query.FilterString, то увидите, что единственная цитата была экранирована:

"(PartitionKey eq 'what' s up') и (RowKey eq 'blah') "