title | description | services | documentationcenter | author | manager | editor | ms.assetid | ms.service | ms.workload | ms.tgt_pltfrm | ms.devlang | ms.topic | ms.date | ms.author |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Get started with Azure Table storage using .NET | Microsoft Docs |
Store structured data in the cloud using Azure Table storage, a NoSQL data store. |
storage |
.net |
mmacy |
timlt |
tysonn |
fe46d883-7bed-49dd-980e-5c71df36adb3 |
storage |
storage |
na |
dotnet |
hero-article |
12/08/2016 |
marsma |
[!INCLUDE storage-selector-table-include]
[!INCLUDE storage-try-azure-tools-tables]
Azure Table storage is a service that stores structured NoSQL data in the cloud. Table storage is a key/attribute store with a schemaless design. Because Table storage is schemaless, it's easy to adapt your data as the needs of your application evolve. Access to data is fast and cost-effective for all kinds of applications. Table storage is typically significantly lower in cost than traditional SQL for similar volumes of data.
You can use Table storage to store flexible datasets, such as user data for web applications, address books, device information, and any other type of metadata that your service requires. You can store any number of entities in a table, and a storage account may contain any number of tables, up to the capacity limit of the storage account.
This tutorial shows how to write .NET code for some common scenarios using Azure Table storage, including creating and deleting a table and inserting, updating, deleting, and querying table data.
Prerequisites:
- Microsoft Visual Studio
- Azure Storage Client Library for .NET
- Azure Configuration Manager for .NET
- An Azure storage account
[!INCLUDE storage-dotnet-client-library-version-include]
For additional examples using Table storage, see Getting Started with Azure Table Storage in .NET. You can download the sample application and run it, or browse the code on GitHub.
[!INCLUDE storage-table-concepts-include]
[!INCLUDE storage-create-account-include]
[!INCLUDE storage-development-environment-include]
Add the following using statements to the top of the program.cs
file:
using Microsoft.Azure; // Namespace for CloudConfigurationManager
using Microsoft.WindowsAzure.Storage; // Namespace for CloudStorageAccount
using Microsoft.WindowsAzure.Storage.Table; // Namespace for Table storage types
[!INCLUDE storage-cloud-configuration-manager-include]
The CloudTableClient class enables you to retrieve tables and entities stored in Table storage. Here's one way to create the service client:
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
Now you are ready to write code that reads data from and writes data to Table storage.
This example shows how to create a table if it does not already exist:
// Retrieve the storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Retrieve a reference to the table.
CloudTable table = tableClient.GetTableReference("people");
// Create the table if it doesn't exist.
table.CreateIfNotExists();
Entities map to C# objects by using a custom class derived from TableEntity. To add an entity to a table, create a class that defines the properties of your entity. The following code defines an entity class that uses the customer's first name as the row key and last name as the partition key. Together, an entity's partition and row key uniquely identify the entity in the table. Entities with the same partition key can be queried faster than those with different partition keys, but using diverse partition keys allows for greater scalability of parallel operations. For any property that should be stored in the Table service, the property must be a public property of a supported type that exposes both setting and retrieving values. Also, your entity type must expose a parameter-less constructor.
public class CustomerEntity : TableEntity
{
public CustomerEntity(string lastName, string firstName)
{
this.PartitionKey = lastName;
this.RowKey = firstName;
}
public CustomerEntity() { }
public string Email { get; set; }
public string PhoneNumber { get; set; }
}
Table operations that involve entities are performed via the CloudTable object that you created earlier in the "Create a table" section. The operation to be performed is represented by a TableOperation object. The following code example shows the creation of the CloudTable object and then a CustomerEntity object. To prepare the operation, a TableOperation object is created to insert the customer entity into the table. Finally, the operation is executed by calling CloudTable.Execute.
// Retrieve the storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Create the CloudTable object that represents the "people" table.
CloudTable table = tableClient.GetTableReference("people");
// Create a new customer entity.
CustomerEntity customer1 = new CustomerEntity("Harp", "Walter");
customer1.Email = "[email protected]";
customer1.PhoneNumber = "425-555-0101";
// Create the TableOperation object that inserts the customer entity.
TableOperation insertOperation = TableOperation.Insert(customer1);
// Execute the insert operation.
table.Execute(insertOperation);
You can insert a batch of entities into a table in one write operation. Some other notes on batch operations:
- You can perform updates, deletes, and inserts in the same single batch operation.
- A single batch operation can include up to 100 entities.
- All entities in a single batch operation must have the same partition key.
- While it is possible to perform a query as a batch operation, it must be the only operation in the batch.
The following code example creates two entity objects and adds each to TableBatchOperation by using the Insert method. Then, CloudTable.Execute is called to execute the operation.
// Retrieve the storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Create the CloudTable object that represents the "people" table.
CloudTable table = tableClient.GetTableReference("people");
// Create the batch operation.
TableBatchOperation batchOperation = new TableBatchOperation();
// Create a customer entity and add it to the table.
CustomerEntity customer1 = new CustomerEntity("Smith", "Jeff");
customer1.Email = "[email protected]";
customer1.PhoneNumber = "425-555-0104";
// Create another customer entity and add it to the table.
CustomerEntity customer2 = new CustomerEntity("Smith", "Ben");
customer2.Email = "[email protected]";
customer2.PhoneNumber = "425-555-0102";
// Add both customer entities to the batch insert operation.
batchOperation.Insert(customer1);
batchOperation.Insert(customer2);
// Execute the batch operation.
table.ExecuteBatch(batchOperation);
To query a table for all entities in a partition, use a TableQuery object. The following code example specifies a filter for entities where 'Smith' is the partition key. This example prints the fields of each entity in the query results to the console.
// Retrieve the storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Create the CloudTable object that represents the "people" table.
CloudTable table = tableClient.GetTableReference("people");
// Construct the query operation for all customer entities where PartitionKey="Smith".
TableQuery<CustomerEntity> query = new TableQuery<CustomerEntity>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "Smith"));
// Print the fields for each customer.
foreach (CustomerEntity entity in table.ExecuteQuery(query))
{
Console.WriteLine("{0}, {1}\t{2}\t{3}", entity.PartitionKey, entity.RowKey,
entity.Email, entity.PhoneNumber);
}
If you don't want to query all the entities in a partition, you can specify a range by combining the partition key filter with a row key filter. The following code example uses two filters to get all entities in partition 'Smith' where the row key (first name) starts with a letter earlier than 'E' in the alphabet and then prints the query results.
// Retrieve the storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Create the CloudTable object that represents the "people" table.
CloudTable table = tableClient.GetTableReference("people");
// Create the table query.
TableQuery<CustomerEntity> rangeQuery = new TableQuery<CustomerEntity>().Where(
TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "Smith"),
TableOperators.And,
TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThan, "E")));
// Loop through the results, displaying information about the entity.
foreach (CustomerEntity entity in table.ExecuteQuery(rangeQuery))
{
Console.WriteLine("{0}, {1}\t{2}\t{3}", entity.PartitionKey, entity.RowKey,
entity.Email, entity.PhoneNumber);
}
You can write a query to retrieve a single, specific entity. The following code uses TableOperation to specify the customer 'Ben Smith'. This method returns just one entity rather than a collection, and the returned value in TableResult.Result is a CustomerEntity object. Specifying both partition and row keys in a query is the fastest way to retrieve a single entity from the Table service.
// Retrieve the storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Create the CloudTable object that represents the "people" table.
CloudTable table = tableClient.GetTableReference("people");
// Create a retrieve operation that takes a customer entity.
TableOperation retrieveOperation = TableOperation.Retrieve<CustomerEntity>("Smith", "Ben");
// Execute the retrieve operation.
TableResult retrievedResult = table.Execute(retrieveOperation);
// Print the phone number of the result.
if (retrievedResult.Result != null)
Console.WriteLine(((CustomerEntity)retrievedResult.Result).PhoneNumber);
else
Console.WriteLine("The phone number could not be retrieved.");
To update an entity, retrieve it from the Table service, modify the entity object, and then save the changes back to the Table service. The following code changes an existing customer's phone number. Instead of calling Insert, this code uses Replace. This causes the entity to be fully replaced on the server, unless the entity on the server has changed since it was retrieved, in which case the operation will fail. This failure is to prevent your application from inadvertently overwriting a change made between the retrieval and update by another component of your application. The proper handling of this failure is to retrieve the entity again, make your changes (if still valid), and then perform another Replace operation. The next section will show you how to override this behavior.
// Retrieve the storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Create the CloudTable object that represents the "people" table.
CloudTable table = tableClient.GetTableReference("people");
// Create a retrieve operation that takes a customer entity.
TableOperation retrieveOperation = TableOperation.Retrieve<CustomerEntity>("Smith", "Ben");
// Execute the operation.
TableResult retrievedResult = table.Execute(retrieveOperation);
// Assign the result to a CustomerEntity object.
CustomerEntity updateEntity = (CustomerEntity)retrievedResult.Result;
if (updateEntity != null)
{
// Change the phone number.
updateEntity.PhoneNumber = "425-555-0105";
// Create the Replace TableOperation.
TableOperation updateOperation = TableOperation.Replace(updateEntity);
// Execute the operation.
table.Execute(updateOperation);
Console.WriteLine("Entity updated.");
}
else
Console.WriteLine("Entity could not be retrieved.");
Replace operations will fail if the entity has been changed since it was retrieved from the server. Furthermore, you must retrieve the entity from the server first in order for the Replace operation to be successful. Sometimes, however, you don't know if the entity exists on the server and the current values stored in it are irrelevant. Your update should overwrite them all. To accomplish this, you would use an InsertOrReplace operation. This operation inserts the entity if it doesn't exist, or replaces it if it does, regardless of when the last update was made. In the following code example, the customer entity for Ben Smith is still retrieved, but it is then saved back to the server via InsertOrReplace. Any updates made to the entity between the retrieval and update operations will be overwritten.
// Retrieve the storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Create the CloudTable object that represents the "people" table.
CloudTable table = tableClient.GetTableReference("people");
// Create a retrieve operation that takes a customer entity.
TableOperation retrieveOperation = TableOperation.Retrieve<CustomerEntity>("Smith", "Ben");
// Execute the operation.
TableResult retrievedResult = table.Execute(retrieveOperation);
// Assign the result to a CustomerEntity object.
CustomerEntity updateEntity = (CustomerEntity)retrievedResult.Result;
if (updateEntity != null)
{
// Change the phone number.
updateEntity.PhoneNumber = "425-555-1234";
// Create the InsertOrReplace TableOperation.
TableOperation insertOrReplaceOperation = TableOperation.InsertOrReplace(updateEntity);
// Execute the operation.
table.Execute(insertOrReplaceOperation);
Console.WriteLine("Entity was updated.");
}
else
Console.WriteLine("Entity could not be retrieved.");
A table query can retrieve just a few properties from an entity instead of all the entity properties. This technique, called projection, reduces bandwidth and can improve query performance, especially for large entities. The query in the following code returns only the email addresses of entities in the table. This is done by using a query of DynamicTableEntity and also EntityResolver. You can learn more about projection on the Introducing Upsert and Query Projection blog post. Note that projection is not supported on the local storage emulator, so this code runs only when you're using an account on the Table service.
// Retrieve the storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Create the CloudTable that represents the "people" table.
CloudTable table = tableClient.GetTableReference("people");
// Define the query, and select only the Email property.
TableQuery<DynamicTableEntity> projectionQuery = new TableQuery<DynamicTableEntity>().Select(new string[] { "Email" });
// Define an entity resolver to work with the entity after retrieval.
EntityResolver<string> resolver = (pk, rk, ts, props, etag) => props.ContainsKey("Email") ? props["Email"].StringValue : null;
foreach (string projectedEmail in table.ExecuteQuery(projectionQuery, resolver, null, null))
{
Console.WriteLine(projectedEmail);
}
You can easily delete an entity after you have retrieved it, by using the same pattern shown for updating an entity. The following code retrieves and deletes a customer entity.
// Retrieve the storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Create the CloudTable that represents the "people" table.
CloudTable table = tableClient.GetTableReference("people");
// Create a retrieve operation that expects a customer entity.
TableOperation retrieveOperation = TableOperation.Retrieve<CustomerEntity>("Smith", "Ben");
// Execute the operation.
TableResult retrievedResult = table.Execute(retrieveOperation);
// Assign the result to a CustomerEntity.
CustomerEntity deleteEntity = (CustomerEntity)retrievedResult.Result;
// Create the Delete TableOperation.
if (deleteEntity != null)
{
TableOperation deleteOperation = TableOperation.Delete(deleteEntity);
// Execute the operation.
table.Execute(deleteOperation);
Console.WriteLine("Entity deleted.");
}
else
Console.WriteLine("Could not retrieve the entity.");
Finally, the following code example deletes a table from a storage account. A table that has been deleted will be unavailable to be re-created for a period of time following the deletion.
// Retrieve the storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Create the CloudTable that represents the "people" table.
CloudTable table = tableClient.GetTableReference("people");
// Delete the table it if exists.
table.DeleteIfExists();
If you are reading a large number of entities, and you want to process/display entities as they are retrieved rather than waiting for them all to return, you can retrieve entities by using a segmented query. This example shows how to return results in pages by using the Async-Await pattern so that execution is not blocked while you're waiting for a large set of results to return. For more details on using the Async-Await pattern in .NET, see Asynchronous programming with Async and Await (C# and Visual Basic).
// Initialize a default TableQuery to retrieve all the entities in the table.
TableQuery<CustomerEntity> tableQuery = new TableQuery<CustomerEntity>();
// Initialize the continuation token to null to start from the beginning of the table.
TableContinuationToken continuationToken = null;
do
{
// Retrieve a segment (up to 1,000 entities).
TableQuerySegment<CustomerEntity> tableQueryResult =
await table.ExecuteQuerySegmentedAsync(tableQuery, continuationToken);
// Assign the new continuation token to tell the service where to
// continue on the next iteration (or null if it has reached the end).
continuationToken = tableQueryResult.ContinuationToken;
// Print the number of rows retrieved.
Console.WriteLine("Rows retrieved {0}", tableQueryResult.Results.Count);
// Loop until a null continuation token is received, indicating the end of the table.
} while(continuationToken != null);
Now that you've learned the basics of Table storage, follow these links to learn about more complex storage tasks:
- See more Table storage samples in Getting Started with Azure Table Storage in .NET
- View the Table service reference documentation for complete details about available APIs:
- Learn how to simplify the code you write to work with Azure Storage by using the Azure WebJobs SDK
- View more feature guides to learn about additional options for storing data in Azure.
- Get started with Azure Blob storage using .NET to store unstructured data.
- Connect to SQL Database by using .NET (C#) to store relational data.