title | description | services | author | ms.service | ms.component | ms.devlang | ms.topic | ms.date | ms.author |
---|---|---|---|---|---|---|---|---|---|
How to use Azure Table Storage and Azure Cosmos DB Table API with C++ |
Store structured data in the cloud using Azure Table storage or the Azure Cosmos DB Table API. |
cosmos-db |
SnehaGunda |
cosmos-db |
cosmosdb-table |
cpp |
sample |
04/05/2018 |
sngun |
[!INCLUDE storage-selector-table-include] [!INCLUDE storage-table-applies-to-storagetable-and-cosmos]
This guide will show you how to perform common scenarios by using the Azure Table storage service or Azure Cosmos DB Table API. The samples are written in C++ and use the Azure Storage Client Library for C++. The scenarios covered include creating and deleting a table and working with table entities.
Note
This guide targets the Azure Storage Client Library for C++ version 1.0.0 and above. The recommended version is Storage Client Library 2.2.0, which is available via NuGet or GitHub.
[!INCLUDE cosmos-db-create-azure-service-account]
[!INCLUDE cosmos-db-create-storage-account]
[!INCLUDE cosmos-db-create-tableapi-account]
In this guide, you will use storage features that can be run within a C++ application. To do so, you will need to install the Azure Storage Client Library for C++ and create an Azure storage account in your Azure subscription.
To install the Azure Storage Client Library for C++, you can use the following methods:
-
Linux: Follow the instructions given on the Azure Storage Client Library for C++ README page.
-
Windows: In Visual Studio, click Tools > NuGet Package Manager > Package Manager Console. Type the following command into the NuGet Package Manager console and press Enter.
Install-Package wastorage
Add the following include statements to the top of the C++ file where you want to use the Azure storage APIs to access tables:
#include <was/storage_account.h>
#include <was/table.h>
An Azure Storage client or Cosmos DB client uses a connection string to store endpoints and credentials to access data management services. When running a client application, you must provide the storage connection string or Azure Cosmos DB connection string in the appropriate format.
Use the name of your Storage account and the access key for the Storage account listed in the Azure Portal for the AccountName and AccountKey values. For information on Storage accounts and access keys, see About Azure Storage accounts. This example shows how you can declare a static field to hold the Azure Storage connection string:
// Define the Storage connection string with your values.
const utility::string_t storage_connection_string(U("DefaultEndpointsProtocol=https;AccountName=your_storage_account;AccountKey=your_storage_account_key"));
Use the name of your Azure Cosmos DB account, your primary key, and endpoint listed in the Azure Portal for the Account Name, Primary Key, and Endpoint values. This example shows how you can declare a static field to hold the Azure Cosmos DB connection string:
// Define the Azure Cosmos DB connection string with your values.
const utility::string_t storage_connection_string(U("DefaultEndpointsProtocol=https;AccountName=your_cosmos_db_account;AccountKey=your_cosmos_db_account_key;TableEndpoint=your_cosmos_db_endpoint"));
To test your application in your local Windows-based computer, you can use the Azure storage emulator that is installed with the Azure SDK. The storage emulator is a utility that simulates the Azure Blob, Queue, and Table services available on your local development machine. The following example shows how you can declare a static field to hold the connection string to your local storage emulator:
// Define the connection string with Azure storage emulator.
const utility::string_t storage_connection_string(U("UseDevelopmentStorage=true;"));
To start the Azure storage emulator, click the Start button or press the Windows key. Begin typing Azure Storage Emulator, and then select Microsoft Azure Storage Emulator from the list of applications.
The following samples assume that you have used one of these two methods to get the storage connection string.
You can use the cloud_storage_account class to represent your storage account information. To retrieve your storage account information from the storage connection string, you can use the parse method.
// Retrieve the storage account from the connection string.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
Next, get a reference to a cloud_table_client class, as it lets you get reference objects for tables and entities stored within the Table storage service. The following code creates a cloud_table_client object by using the storage account object we retrieved above:
// Create the table client.
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
A cloud_table_client object lets you get reference objects for tables and entities. The following code creates a cloud_table_client object and uses it to create a new table.
// Retrieve the storage account from the connection string.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
// Create the table client.
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
// Retrieve a reference to a table.
azure::storage::cloud_table table = table_client.get_table_reference(U("people"));
// Create the table if it doesn't exist.
table.create_if_not_exists();
To add an entity to a table, create a new table_entity object and pass it to table_operation::insert_entity. The following code 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 parallel operation scalability. For more information, see Microsoft Azure storage performance and scalability checklist.
The following code creates a new instance of table_entity with some customer data to be stored. The code next calls table_operation::insert_entity to create a table_operation object to insert an entity into a table, and associates the new table entity with it. Finally, the code calls the execute method on the cloud_table object. And the new table_operation sends a request to the Table service to insert the new customer entity into the "people" table.
// Retrieve the storage account from the connection string.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
// Create the table client.
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
// Retrieve a reference to a table.
azure::storage::cloud_table table = table_client.get_table_reference(U("people"));
// Create the table if it doesn't exist.
table.create_if_not_exists();
// Create a new customer entity.
azure::storage::table_entity customer1(U("Harp"), U("Walter"));
azure::storage::table_entity::properties_type& properties = customer1.properties();
properties.reserve(2);
properties[U("Email")] = azure::storage::entity_property(U("[email protected]"));
properties[U("Phone")] = azure::storage::entity_property(U("425-555-0101"));
// Create the table operation that inserts the customer entity.
azure::storage::table_operation insert_operation = azure::storage::table_operation::insert_entity(customer1);
// Execute the insert operation.
azure::storage::table_result insert_result = table.execute(insert_operation);
You can insert a batch of entities to the Table service in one write operation. The following code creates a table_batch_operation object, and then adds three insert operations to it. Each insert operation is added by creating a new entity object, setting its values, and then calling the insert method on the table_batch_operation object to associate the entity with a new insert operation. Then, cloud_table.execute is called to execute the operation.
// Retrieve the storage account from the connection string.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
// Create the table client.
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
// Create a cloud table object for the table.
azure::storage::cloud_table table = table_client.get_table_reference(U("people"));
// Define a batch operation.
azure::storage::table_batch_operation batch_operation;
// Create a customer entity and add it to the table.
azure::storage::table_entity customer1(U("Smith"), U("Jeff"));
azure::storage::table_entity::properties_type& properties1 = customer1.properties();
properties1.reserve(2);
properties1[U("Email")] = azure::storage::entity_property(U("[email protected]"));
properties1[U("Phone")] = azure::storage::entity_property(U("425-555-0104"));
// Create another customer entity and add it to the table.
azure::storage::table_entity customer2(U("Smith"), U("Ben"));
azure::storage::table_entity::properties_type& properties2 = customer2.properties();
properties2.reserve(2);
properties2[U("Email")] = azure::storage::entity_property(U("[email protected]"));
properties2[U("Phone")] = azure::storage::entity_property(U("425-555-0102"));
// Create a third customer entity to add to the table.
azure::storage::table_entity customer3(U("Smith"), U("Denise"));
azure::storage::table_entity::properties_type& properties3 = customer3.properties();
properties3.reserve(2);
properties3[U("Email")] = azure::storage::entity_property(U("[email protected]"));
properties3[U("Phone")] = azure::storage::entity_property(U("425-555-0103"));
// Add customer entities to the batch insert operation.
batch_operation.insert_or_replace_entity(customer1);
batch_operation.insert_or_replace_entity(customer2);
batch_operation.insert_or_replace_entity(customer3);
// Execute the batch operation.
std::vector<azure::storage::table_result> results = table.execute_batch(batch_operation);
Some things to note on batch operations:
- You can perform up to 100 insert, delete, merge, replace, insert-or-merge, and insert-or-replace operations in any combination in a single batch.
- A batch operation can have a retrieve operation, if it is the only operation in the batch.
- All entities in a single batch operation must have the same partition key.
- A batch operation is limited to a 4-MB data payload.
To query a table for all entities in a partition, use a table_query 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.
Note
These methods are not currently supported for C++ in Azure Cosmos DB.
// Retrieve the storage account from the connection string.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
// Create the table client.
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
// Create a cloud table object for the table.
azure::storage::cloud_table table = table_client.get_table_reference(U("people"));
// Construct the query operation for all customer entities where PartitionKey="Smith".
azure::storage::table_query query;
query.set_filter_string(azure::storage::table_query::generate_filter_condition(U("PartitionKey"), azure::storage::query_comparison_operator::equal, U("Smith")));
// Execute the query.
azure::storage::table_query_iterator it = table.execute_query(query);
// Print the fields for each customer.
azure::storage::table_query_iterator end_of_results;
for (; it != end_of_results; ++it)
{
const azure::storage::table_entity::properties_type& properties = it->properties();
std::wcout << U("PartitionKey: ") << it->partition_key() << U(", RowKey: ") << it->row_key()
<< U(", Property1: ") << properties.at(U("Email")).string_value()
<< U(", Property2: ") << properties.at(U("Phone")).string_value() << std::endl;
}
The query in this example brings all the entities that match the filter criteria. If you have large tables and need to download the table entities often, we recommend that you store your data in Azure storage blobs instead.
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.
Note
These methods are not currently supported for C++ in Azure Cosmos DB.
// Retrieve the storage account from the connection string.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
// Create the table client.
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
// Create a cloud table object for the table.
azure::storage::cloud_table table = table_client.get_table_reference(U("people"));
// Create the table query.
azure::storage::table_query query;
query.set_filter_string(azure::storage::table_query::combine_filter_conditions(
azure::storage::table_query::generate_filter_condition(U("PartitionKey"),
azure::storage::query_comparison_operator::equal, U("Smith")),
azure::storage::query_logical_operator::op_and,
azure::storage::table_query::generate_filter_condition(U("RowKey"), azure::storage::query_comparison_operator::less_than, U("E"))));
// Execute the query.
azure::storage::table_query_iterator it = table.execute_query(query);
// Loop through the results, displaying information about the entity.
azure::storage::table_query_iterator end_of_results;
for (; it != end_of_results; ++it)
{
const azure::storage::table_entity::properties_type& properties = it->properties();
std::wcout << U("PartitionKey: ") << it->partition_key() << U(", RowKey: ") << it->row_key()
<< U(", Property1: ") << properties.at(U("Email")).string_value()
<< U(", Property2: ") << properties.at(U("Phone")).string_value() << std::endl;
}
You can write a query to retrieve a single, specific entity. The following code uses table_operation::retrieve_entity to specify the customer 'Jeff Smith'. This method returns just one entity, rather than a collection, and the returned value is in table_result. Specifying both partition and row keys in a query is the fastest way to retrieve a single entity from the Table service.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
// Create the table client.
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
// Create a cloud table object for the table.
azure::storage::cloud_table table = table_client.get_table_reference(U("people"));
// Retrieve the entity with partition key of "Smith" and row key of "Jeff".
azure::storage::table_operation retrieve_operation = azure::storage::table_operation::retrieve_entity(U("Smith"), U("Jeff"));
azure::storage::table_result retrieve_result = table.execute(retrieve_operation);
// Output the entity.
azure::storage::table_entity entity = retrieve_result.entity();
const azure::storage::table_entity::properties_type& properties = entity.properties();
std::wcout << U("PartitionKey: ") << entity.partition_key() << U(", RowKey: ") << entity.row_key()
<< U(", Property1: ") << properties.at(U("Email")).string_value()
<< U(", Property2: ") << properties.at(U("Phone")).string_value() << std::endl;
To replace 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 and email address. Instead of calling table_operation::insert_entity, this code uses table_operation::replace_entity. 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 table_operation::replace_entity operation. The next section will show you how to override this behavior.
// Retrieve the storage account from the connection string.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
// Create the table client.
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
// Create a cloud table object for the table.
azure::storage::cloud_table table = table_client.get_table_reference(U("people"));
// Replace an entity.
azure::storage::table_entity entity_to_replace(U("Smith"), U("Jeff"));
azure::storage::table_entity::properties_type& properties_to_replace = entity_to_replace.properties();
properties_to_replace.reserve(2);
// Specify a new phone number.
properties_to_replace[U("Phone")] = azure::storage::entity_property(U("425-555-0106"));
// Specify a new email address.
properties_to_replace[U("Email")] = azure::storage::entity_property(U("[email protected]"));
// Create an operation to replace the entity.
azure::storage::table_operation replace_operation = azure::storage::table_operation::replace_entity(entity_to_replace);
// Submit the operation to the Table service.
azure::storage::table_result replace_result = table.execute(replace_operation);
table_operation::replace_entity 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 table_operation::replace_entity 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 a table_operation::insert_or_replace_entity 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 Jeff Smith is still retrieved, but it is then saved back to the server via table_operation::insert_or_replace_entity. Any updates made to the entity between the retrieval and update operation will be overwritten.
// Retrieve the storage account from the connection string.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
// Create the table client.
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
// Create a cloud table object for the table.
azure::storage::cloud_table table = table_client.get_table_reference(U("people"));
// Insert-or-replace an entity.
azure::storage::table_entity entity_to_insert_or_replace(U("Smith"), U("Jeff"));
azure::storage::table_entity::properties_type& properties_to_insert_or_replace = entity_to_insert_or_replace.properties();
properties_to_insert_or_replace.reserve(2);
// Specify a phone number.
properties_to_insert_or_replace[U("Phone")] = azure::storage::entity_property(U("425-555-0107"));
// Specify an email address.
properties_to_insert_or_replace[U("Email")] = azure::storage::entity_property(U("[email protected]"));
// Create an operation to insert-or-replace the entity.
azure::storage::table_operation insert_or_replace_operation = azure::storage::table_operation::insert_or_replace_entity(entity_to_insert_or_replace);
// Submit the operation to the Table service.
azure::storage::table_result insert_or_replace_result = table.execute(insert_or_replace_operation);
A query to a table can retrieve just a few properties from an entity. The query in the following code uses the table_query::set_select_columns method to return only the email addresses of entities in the table.
// Retrieve the storage account from the connection string.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
// Create the table client.
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
// Create a cloud table object for the table.
azure::storage::cloud_table table = table_client.get_table_reference(U("people"));
// Define the query, and select only the Email property.
azure::storage::table_query query;
std::vector<utility::string_t> columns;
columns.push_back(U("Email"));
query.set_select_columns(columns);
// Execute the query.
azure::storage::table_query_iterator it = table.execute_query(query);
// Display the results.
azure::storage::table_query_iterator end_of_results;
for (; it != end_of_results; ++it)
{
std::wcout << U("PartitionKey: ") << it->partition_key() << U(", RowKey: ") << it->row_key();
const azure::storage::table_entity::properties_type& properties = it->properties();
for (auto prop_it = properties.begin(); prop_it != properties.end(); ++prop_it)
{
std::wcout << ", " << prop_it->first << ": " << prop_it->second.str();
}
std::wcout << std::endl;
}
Note
Querying a few properties from an entity is a more efficient operation than retrieving all properties.
You can easily delete an entity after you have retrieved it. Once the entity is retrieved, call table_operation::delete_entity with the entity to delete. Then call the cloud_table.execute method. The following code retrieves and deletes an entity with a partition key of "Smith" and a row key of "Jeff".
// Retrieve the storage account from the connection string.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
// Create the table client.
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
// Create a cloud table object for the table.
azure::storage::cloud_table table = table_client.get_table_reference(U("people"));
// Create an operation to retrieve the entity with partition key of "Smith" and row key of "Jeff".
azure::storage::table_operation retrieve_operation = azure::storage::table_operation::retrieve_entity(U("Smith"), U("Jeff"));
azure::storage::table_result retrieve_result = table.execute(retrieve_operation);
// Create an operation to delete the entity.
azure::storage::table_operation delete_operation = azure::storage::table_operation::delete_entity(retrieve_result.entity());
// Submit the delete operation to the Table service.
azure::storage::table_result delete_result = table.execute(delete_operation);
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.
azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
// Create the table client.
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
// Create a cloud table object for the table.
azure::storage::cloud_table table = table_client.get_table_reference(U("people"));
// Delete the table if it exists
if (table.delete_table_if_exists())
{
std::cout << "Table deleted!";
}
else
{
std::cout << "Table didn't exist";
}
-
Build errors in Visual Studio 2017 Community Edition
If your project gets build errors because of the include files storage_account.h and table.h, remove the /permissive- compiler switch.
- In Solution Explorer, right-click your project and select Properties.
- In the Property Pages dialog box, expand Configuration Properties, expand C/C++, and select Language.
- Set Conformance mode to No.
Follow these links to learn more about Azure Storage and the Table API in Azure Cosmos DB:
- Introduction to the Table API
- Microsoft Azure Storage Explorer is a free, standalone app from Microsoft that enables you to work visually with Azure Storage data on Windows, macOS, and Linux.
- List Azure Storage resources in C++
- Storage Client Library for C++ reference
- Azure Storage documentation