Working with Azure Table Storage using .NET
This document provides a comprehensive guide to interacting with Azure Table Storage using the .NET SDK. It covers essential operations such as creating tables, inserting entities, querying data, updating entities, and deleting entities.
Introduction to Azure Table Storage
Azure Table Storage is a NoSQL key-attribute store that accommodates unstructured data. It's a cost-effective way to store large amounts of structured, non-relational data that can be accessed from anywhere in the world. Table storage is a NoSQL datastore that accepts authenticated calls across HTTP or HTTPS from any HTTP client. It is also known as Azure Cosmos DB Table API.
Prerequisites
- An Azure subscription.
- An Azure Storage account.
- Visual Studio or an equivalent .NET development environment.
- The latest Azure Table Storage SDK for .NET.
Setting up the Project
To begin, create a new .NET project (e.g., a Console Application) and install the necessary NuGet package:
dotnet add package Azure.Data.Tables
Connecting to Azure Table Storage
You'll need your storage account connection string or endpoint and key. The connection string is the most common method.
using Azure.Data.Tables;
// Replace with your actual connection string
string connectionString = "YOUR_STORAGE_ACCOUNT_CONNECTION_STRING";
string tableName = "MySampleTable";
// Create a TableServiceClient using the connection string
TableServiceClient tableServiceClient = new TableServiceClient(connectionString);
// Get a TableClient for the specific table
TableClient tableClient = tableServiceClient.GetTableClient(tableName);
// Optionally, create the table if it doesn't exist
tableClient.CreateIfNotExists();
Console.WriteLine($"Table '{tableName}' is ready.");
Entities in Table Storage
Entities are the core units of data in Azure Table Storage. Each entity is a set of properties, similar to a row in a database table. An entity must have at least two properties:
- PartitionKey: Groups entities together.
- RowKey: Uniquely identifies an entity within a partition.
Together, PartitionKey and RowKey form the entity's primary key.
Defining an Entity
You can define your entity as a class that inherits from ITableEntity or by using TableEntity directly.
using Azure;
using Azure.Data.Tables;
public class ProductEntity : ITableEntity
{
public string PartitionKey { get; set; } = string.Empty;
public string RowKey { get; set; } = string.Empty;
public DateTimeOffset? Timestamp { get; set; }
public ETag ETag { get; set; }
public string ProductName { get; set; } = string.Empty;
public int StockQuantity { get; set; }
public double Price { get; set; }
}
CRUD Operations
Inserting an Entity
To insert a new entity, create an instance of your entity class and use the AddEntity method.
// Example: Creating and inserting a product entity
ProductEntity product = new ProductEntity
{
PartitionKey = "Electronics",
RowKey = "SKU12345",
ProductName = "Wireless Mouse",
StockQuantity = 150,
Price = 25.99
};
try
{
tableClient.AddEntity(product);
Console.WriteLine($"Product '{product.ProductName}' added successfully.");
}
catch (RequestFailedException ex)
{
Console.WriteLine($"Error adding entity: {ex.Message}");
}
Querying Entities
You can query entities using OData filter expressions or LINQ.
Using OData Filter
// Filter to find products in the 'Electronics' partition with quantity > 100
string filter = "PartitionKey eq 'Electronics' and StockQuantity gt 100";
Pageable<ProductEntity> queryResults = tableClient.Query<ProductEntity>(filter: filter);
Console.WriteLine("Products with Stock Quantity > 100 in Electronics:");
foreach (Page<ProductEntity> page in queryResults.AsPages())
{
foreach (ProductEntity entity in page.Values)
{
Console.WriteLine($"- {entity.ProductName} (Stock: {entity.StockQuantity}, Price: {entity.Price})");
}
}
Using LINQ
// LINQ query to find products with price less than 50
var linqQuery = tableClient.Query<ProductEntity>(e => e.Price < 50.0);
Console.WriteLine("Products with Price < 50:");
foreach (var entity in linqQuery)
{
Console.WriteLine($"- {entity.ProductName} (Price: {entity.Price})");
}
Updating an Entity
You can update an entity using UpsertEntity (inserts if not exists, updates if exists) or UpdateEntity (only updates if exists).
// Retrieve the entity first to ensure it exists and get ETag
Response<ProductEntity> existingEntityResponse = tableClient.GetEntity<ProductEntity>>("Electronics", "SKU12345");
ProductEntity productToUpdate = existingEntityResponse.Value;
if (productToUpdate != null)
{
productToUpdate.StockQuantity += 20; // Increase stock
productToUpdate.Price *= 0.95; // Apply a 5% discount
try
{
// Use UpsertEntity to update or insert
tableClient.UpsertEntity(productToUpdate, TableUpdateMode.Replace);
Console.WriteLine($"Product '{productToUpdate.ProductName}' updated successfully.");
}
catch (RequestFailedException ex)
{
Console.WriteLine($"Error updating entity: {ex.Message}");
}
}
else
{
Console.WriteLine("Product not found for update.");
}
Deleting an Entity
To delete an entity, you need its PartitionKey and RowKey.
string partitionKeyToDelete = "Electronics";
string rowKeyToDelete = "SKU12345";
try
{
tableClient.DeleteEntity(partitionKeyToDelete, rowKeyToDelete);
Console.WriteLine($"Entity with PartitionKey='{partitionKeyToDelete}' and RowKey='{rowKeyToDelete}' deleted.");
}
catch (RequestFailedException ex)
{
Console.WriteLine($"Error deleting entity: {ex.Message}");
}
Advanced Concepts
- Batch Operations: Perform multiple insert, update, or delete operations in a single request.
- Transactions: For atomic operations within a single partition.
- Data Types: Table storage supports various data types.
- Indexing: Understand how
PartitionKeyandRowKeyimpact query performance.
PartitionKey and RowKey carefully to optimize for your most common query patterns. This is crucial for performance in NoSQL databases.
Conclusion
Azure Table Storage provides a scalable and cost-effective solution for managing large volumes of structured NoSQL data. The Azure SDK for .NET simplifies the integration, allowing developers to perform all necessary data operations with ease.