TableQuery <T> из Azure TableStorage, который фильтрует PartitionKey

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

public List<T> GetEntities<T>(string partitionKey, T entity) where T : TableEntity
    {
        try
        {
            var tableClient = _account.CreateCloudTableClient();
            var table = tableClient.GetTableReference(entity.GetType().Name.ToLower());
            var exQuery =
                new TableQuery<T>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal,
                                                                             partitionKey));

            var results = table.ExecuteQuery(exQuery).Select(ent => (T) ent).ToList();
            return results;
        }
        catch (StorageException ex)
        {
            //TODO: Add more trace info
            Trace.TraceInformation("Unable to retrieve entity based on query specs");
            return null;
        }
    }

Однако, он не работает на

new TableQuery<T>

потому что у TElement нет конструктора без параметров.

Ответ 1

Как вы упомянули в своем вопросе, T должен иметь конструктор без параметров. Следовательно, пожалуйста, измените определение своего метода следующим образом:

public List<T> GetEntities<T>(string partitionKey, T entity) where T : TableEntity, new ()

Ответ 2

Я написал небольшой общий репозиторий для хранения таблиц:

 public class CloudTableRepository<T> where T : ITableEntity,new ()
{
    private readonly string _tableName;
    private CloudTable _table;

    public CloudTableRepository(string tableName)
    {
        _tableName = tableName;
        InitializeTable();
    }

    #region Public Methods

    public virtual async Task<List<T>> GetPartitionAsync(string partitionKey, int takeCount = 1000)
    {
        var result = new List<T>();
        var query =
            new TableQuery<T>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal,
                partitionKey));
        query.TakeCount = takeCount;
        TableContinuationToken tableContinuationToken = null;
        do
        {
            var queryResponse = await _table.ExecuteQuerySegmentedAsync(query, tableContinuationToken);
            tableContinuationToken = queryResponse.ContinuationToken;
            result.AddRange(queryResponse.Results);
        } while (tableContinuationToken != null);
        return result;
    }

    public virtual async Task<TableResult> GetSingleAsync(string partitionKey, string rowKey)
    {
       return  await GetSingle(partitionKey, rowKey);
    }

    public virtual async Task<T> UpdateAsync(T tableEntityData)
    {
        var updateCallistConfig = await GetSingleAsync(tableEntityData.PartitionKey, tableEntityData.RowKey);
        if (updateCallistConfig != null)
        {
            var updateOperation = TableOperation.InsertOrMerge(tableEntityData);
            var tableResult = await _table.ExecuteAsync(updateOperation);
            return (T) tableResult.Result;
        }
        return default(T);
    }

    public virtual async Task<T> AddAsync(T tableEntityData)
    {
        var retrieveOperation = TableOperation.Insert(tableEntityData);
        var tableResult = await _table.ExecuteAsync(retrieveOperation);
        return (T) tableResult.Result;
    }


    #endregion

    #region Private Methods

    private async void InitializeTable()
    {
        var storageAccount =
            CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("TableStorageConnectionString"));
        var tableClient = storageAccount.CreateCloudTableClient();
        _table = tableClient.GetTableReference(_tableName);
        await _table.CreateIfNotExistsAsync();
    }

    private async Task<TableResult> GetSingle(string partitionKey, string rowKey)
    {
        var retrieveOperation = TableOperation.Retrieve<T>(partitionKey, rowKey);
        var tableResult = await _table.ExecuteAsync(retrieveOperation);
        return tableResult; //(T) tableResult.Result;
    }

    #endregion
}

Ответ 3

В дополнение к ответу @serdar-ozler-microsoft вам даже не нужно преобразовывать и отбрасывать сущности для возврата.

Метод CloudTable.ExecuteQuery имеет перегрузку, которая принимает общий тип:

public IEnumerable<TElement> ExecuteQuery<TElement>(
TableQuery<TElement> query,
TableRequestOptions requestOptions = null,
OperationContext operationContext = null)
where TElement : new(), ITableEntity

Вы также можете использовать Linq для фильтрации в службе таблицы.

Чтобы вы могли переписать свой метод следующим образом:

public List<T> GetEntities<T>(string partitionKey, T entity) where T : ITableEntity, new()
{
    try
    {
        var tableClient = _account.CreateCloudTableClient();
        var table = tableClient.GetTableReference(entity.GetType().Name.ToLower());
        return table.CreateQuery<T>().Where(e => e.PartitionKey == partitionKey).ToList();
    }
    catch (StorageException ex)
    {
        //TODO: Add more trace info
        Trace.TraceInformation("Unable to retrieve entity based on query specs");
        return null;
    }
}