web-dev-qa-db-ja.com

Azureテーブルストレージクエリを非同期で実行する方法は?クライアントバージョン4.0.1

Azure Storage Clientバージョン4.0.1で非同期クエリを実行したい

メソッドExecuteQueryAsync()はありません。

私は何かが欠けていますか? ExecuteQuerySegmentedAsyncを引き続き使用する必要がありますか?ありがとう。

56
Jose Ch.

最終的に、ExecuteQuerySegmentedAsyncを使用する拡張メソッドを作成します。この解決策が最適かどうかはわかりません。コメントがありましたら、お気軽にどうぞ。

public static async Task<IList<T>> ExecuteQueryAsync<T>(this CloudTable table, TableQuery<T> query, CancellationToken ct = default(CancellationToken), Action<IList<T>> onProgress = null) where T : ITableEntity, new()
    {

        var items = new List<T>();
        TableContinuationToken token = null;

        do
        {

            TableQuerySegment<T> seg = await table.ExecuteQuerySegmentedAsync<T>(query, token);
            token = seg.ContinuationToken;
            items.AddRange(seg);
            if (onProgress != null) onProgress(items);

        } while (token != null && !ct.IsCancellationRequested);

        return items;
    }
74
Jose Ch.

テーブルクエリにtake句が含まれている場合、指定されたソリューションはクエリで要求されたよりも多くのアイテムを返します。 while式を少し変更するだけで問題が解決します。

public static async Task<IList<T>> ExecuteQueryAsync<T>(this CloudTable table, TableQuery<T> query, CancellationToken ct = default(CancellationToken), Action<IList<T>> onProgress = null) where T : ITableEntity, new()
{
    var runningQuery = new TableQuery<T>()
    {
        FilterString = query.FilterString,
        SelectColumns = query.SelectColumns
    };

    var items = new List<T>();
    TableContinuationToken token = null;

    do
    {
        runningQuery.TakeCount = query.TakeCount - items.Count;

        TableQuerySegment<T> seg = await table.ExecuteQuerySegmentedAsync<T>(runningQuery, token);
        token = seg.ContinuationToken;
        items.AddRange(seg);
        if (onProgress != null) onProgress(items);

    } while (token != null && !ct.IsCancellationRequested && (query.TakeCount == null || items.Count < query.TakeCount.Value));

    return items;
}

[〜#〜] edited [〜#〜]:PaulGの提案のおかげで、クエリにtake句が含まれ、ExecuteQuerySegmentedAsyncが複数のパスでアイテムを返す場合の結果カウントの問題が修正されました。

14
Davor

これは、@JoseCh.の回答に追加されます。

EntityResolverを指定できる拡張メソッドは次のとおりです。

public static async Task<IList<TResult>> ExecuteQueryAsync<T, TResult>(this CloudTable table, TableQuery query, EntityResolver<TResult> resolver, Action<IList<TResult>> onProgress = null, CancellationToken cancelToken = default(CancellationToken))
            where T : ITableEntity, new()
{
    var items = new List<TResult>();
    TableContinuationToken token = null;

    do
    {
        TableQuerySegment<TResult> seg = await table.ExecuteQuerySegmentedAsync(query: query, resolver: resolver, token: new TableContinuationToken(), cancellationToken: cancelToken).ConfigureAwait(false);
        token = seg.ContinuationToken;
        items.AddRange(seg);
        onProgress?.Invoke(items);
     }
     while (token != null && !cancelToken.IsCancellationRequested);
         return items;
     }
}

ストレージ内の単一列の結果セットのみを返す場合に使用できます。

// maps to a column name in storage
string propertyName = nameof(example.Category);

// Define the query, and select only the Category property.
var projectionQuery = new TableQuery().Select(new string[] { propertyName });

// Define an entity resolver to work with the entity after retrieval.
EntityResolver<string> resolver = (pk, rk, ts, props, etag) => props.ContainsKey(propertyName) ? props[propertyName].StringValue : null;

var categories = (await someTable.ExecuteQueryAsync<DynamicTableEntity, string>(query: projectionQuery, resolver: resolver).ConfigureAwait(false)).ToList()
0
Zze