CRUD Operations with Azure Table Storage in an Azure Function – U

In the earlier posts, we enlightened ourselves with creation and retrieval of records from Azure Table Storage using Azure Web Functions. In this segment, we will attempt to update a record.

Let us once again look at our table before proceeding further.

In the first approach, we will attempt to update the record based on the RowKey and PartitionKey provided by the request. Let us go ahead and write our method now.

[FunctionName("Update")]
public static async Task<IActionResult> Update(
    [HttpTrigger(AuthorizationLevel.Anonymous,"post",Route = null)] HttpRequest request,
    [Table("todos")]CloudTable todoTable,
    ILogger log)
{
    log.LogInformation("Request to update Record");

    string requestBody = await new StreamReader(request.Body).ReadToEndAsync();
    var data = JsonConvert.DeserializeObject<TodoDto>(requestBody);

    var rowKeyToUpdate= request.Query[nameof(TableEntity.RowKey)];
    var partitionKeyToUpdate= request.Query[nameof(TableEntity.PartitionKey)];

    var tableEntity = new TodoTableEntity
    {
        RowKey = rowKeyToUpdate,
        PartitionKey = partitionKeyToUpdate,
        Title = data.Title,
        Description = data.Description,
        IsCompleted = data.IsCompletd,
        ETag = "*"
    };

    var updateOperation = TableOperation.Replace(tableEntity);
    var result = await todoTable.ExecuteAsync(updateOperation);
    return new OkObjectResult(result);
}

I will skip the Bindings here since we have learned about the same in the previous posts. We will first create an instance of record which will have the new value.

var tableEntity = new TodoTableEntity
{
    RowKey = rowKeyToUpdate,
    PartitionKey = partitionKeyToUpdate,
    Title = data.Title,
    Description = data.Description,
    IsCompleted = data.IsCompletd,
    ETag = "*"
};

Notice that we have used the PartitionKey and Rowkey retrieved from our query (we will address how to fetch it from database, if not given in query later). The other important point to notice here is the presence of the ETag. The Update Table Operation will not be allowed to process without the ETag.

As the next step, we will use the TableOperation to update or replace our record. This turns out to be pretty easy, thanks to the rich collection of methods introduced by Microsoft.

var updateOperation = TableOperation.Replace(tableEntity);
var result = await todoTable.ExecuteAsync(updateOperation);

Now you are ready to hit F5 and test your web function. For example, let us consider the following input.

// Request
http://localhost:7071/api/Update?PartitionKey=L&RowKey=1001

//Body
{
    title:'Learn Azure Func',
    description:'Learn Azure Func with Table Storage',
    isCompleted:'True'
}

We want to flip the IsCompleted Flag to True here. Final result would be.

We could, optimize the code a bit with help of the Bindings we have learned in the previous post. For example, the above code could be rewritten as,

[FunctionName("UpdateUsingBinding")]
public static async Task<IActionResult> UpdateUsingBinding(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "UpdateUsingBinding/{partitionKey}/{rowKey}")] HttpRequest request,
[Table("todos", "{partitionKey}", "{rowKey}")] TodoTableEntity tableEntity,
[Table("todos")] CloudTable todoTable,
    ILogger log)
{
    log.LogInformation("Request to update Record");

    string requestBody = await new StreamReader(request.Body).ReadToEndAsync();
    var data = JsonConvert.DeserializeObject<TodoDto>(requestBody);

    tableEntity.Title = data.Title;
    tableEntity.Description = data.Description;
    tableEntity.IsCompleted = data.IsCompletd;

    var updateOperation = TableOperation.Replace(tableEntity);
    var result = await todoTable.ExecuteAsync(updateOperation);
    return new OkObjectResult(result);
}

As you could notice, we have made using of the Table Bindings to retrieve the record here, which is then updated with new values passed on from the Http Request.

In the last approach for the post, we will address the case when PartitionKey and RowKey is not known to the HttpRequest and we need to fetch it using the Title. Well, as you might have guessed it, it would involve retrieval we learned in the previous posts.

[FunctionName("UpdateWithRetrival")]
public static async Task<IActionResult> UpdateWithRetrival(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest request,
[Table("todos")] CloudTable todoTable,
    ILogger log)
{
    log.LogInformation("Request to update Record");

    string requestBody = await new StreamReader(request.Body).ReadToEndAsync();
    var data = JsonConvert.DeserializeObject<TodoDto>(requestBody);

    var tableQuery = new TableQuery<TodoTableEntity>();

    tableQuery.FilterString = TableQuery.CombineFilters(
        TableQuery.GenerateFilterCondition(nameof(TableEntity.PartitionKey), QueryComparisons.NotEqual, "Key"),
        TableOperators.And,
        TableQuery.GenerateFilterCondition(nameof(TodoTableEntity.Title), QueryComparisons.Equal, data.Title));
    var result = todoTable.ExecuteQuery(tableQuery);

    var itemToUpdate = result.First();
    itemToUpdate.Description = data.Description;
    itemToUpdate.IsCompleted = data.IsCompletd;

    var updateOperation = TableOperation.Replace(itemToUpdate);
    var updateResponse = await todoTable.ExecuteAsync(updateOperation);
    return new OkObjectResult(updateResponse);
}

As you can observe, thanks to the rich API provided by Microsoft, the basic operations with Azure Storage are pretty straightforward. We will address Deletion in the next post, until then, have a great day.