Reputation: 2612
I'm trying to abstract geting all entities from a Table by partitionKey, like so:
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;
}
}
However, It's failing on the
new TableQuery<T>
because the TElement does not have a parameterless constructor.
Upvotes: 19
Views: 19825
Reputation: 4329
I wrote a small generic repository for table storage :
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
}
Upvotes: 8
Reputation: 29491
In addition to @serdar-ozler-microsoft answer, you don't even need to convert and cast the entities to return.
The CloudTable.ExecuteQuery method has an overload that accept a generic type:
public IEnumerable<TElement> ExecuteQuery<TElement>(
TableQuery<TElement> query,
TableRequestOptions requestOptions = null,
OperationContext operationContext = null)
where TElement : new(), ITableEntity
You can also use Linq to filter on the Table Service.
So that you can rewrite your method like that :
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;
}
}
Upvotes: 3
Reputation: 3802
As you also mentioned in your question, T must have a parameterless constructor. Hence, please change the definition of your method as follows:
public List<T> GetEntities<T>(string partitionKey, T entity) where T : TableEntity, new ()
Upvotes: 28