diff --git a/sdk/tables/azure-data-tables/README.md b/sdk/tables/azure-data-tables/README.md index 97ac6b779..5e2ed157a 100644 --- a/sdk/tables/azure-data-tables/README.md +++ b/sdk/tables/azure-data-tables/README.md @@ -53,13 +53,13 @@ Two different clients are provided to interact with the various components of th 1. **`TableClient`** - * Interacts with a specific table (which need not exist yet). * Create, delete, query, and upsert entities within the specified table. - * Create or delete the specified table itself. + * Submit transactional batch operations. 2. **`TableServiceClient`** - * Get and set account settings * Query tables within the account. - + * Create or delete the specified table. ### Entities -Entities are similar to rows. An entity has a **`PartitionKey`**, a **`RowKey`**, and a set of properties. A property is a name value pair, similar to a column. Every entity in a table does not need to have the same properties. +Entities are similar to rows. An entity has a set of properties, including a **`PartitionKey`** and **`RowKey`** which form the primary key of the entity. A property is a name value pair, similar to a column. Every entity in a table does not need to have the same properties. ## Examples @@ -68,7 +68,8 @@ The following sections provide several code snippets covering some of the most c * [Creating and deleting a table](#creating-and-deleting-a-table "Creating and deleting a table") * [Manipulating entities](#manipulating-entities "Manipulating entities") * [Table Service Operations](#table-service-operations "Table Service Operations") - +* [Table Transactions Success](#table-transactions-success "Table Transactions Success") +* [Table Transactions Error](#table-transactions-error "Table Transactions Error") ### Creating and deleting a table In order to Create/Delete a table we need to create a TablesClient first. @@ -79,13 +80,16 @@ In order to Create/Delete a table we need to create a TablesClient first. using namespace Azure::Data::Tables; const std::string TableName = "sample1"; ... -auto tableClient = TableClient::CreateFromConnectionString(..., TableName); -tableClient.Create(); +auto tableServiceClient = TableServiceClient::CreateFromConnectionString(GetConnectionString()); + +// create new table +tableServiceClient.CreateTable(TableName); ``` In order to Delete a table we need to call the delete method on the previously created client. ```cpp -tableClient.Delete(); +// delete existing table +tableServiceClient.DeleteTable(TableName); ``` ### Manipulating entities @@ -99,22 +103,22 @@ using namespace Azure::Data::Tables; const std::string TableName = "sample1"; ... auto tableClient = TableClient::CreateFromConnectionString(..., TableName); -tableClient.Create(); +tableServiceClient.CreateTable(TableName); ``` Then we initialize and populate an entity. ```cpp // init new entity Models::TableEntity entity; - entity.PartitionKey = "P1"; - entity.RowKey = "R1"; - entity.Properties["Name"] = "Azure"; - entity.Properties["Product"] = "Tables"; + entity.SetPartitionKey("P1"); + entity.SetRowKey("R1"); + entity.Properties["Name"] = TableEntityProperty("Azure"); + entity.Properties["Product"] = TableEntityProperty("Tables"); ``` To create the entity on the server we call the CreateEntity method on the table client. ```cpp - tableClient.CreateEntity(entity); + tableClient.AddEntity(entity); ``` To update the entity, assume we made some changes to the entity, we call the UpdateEntity method on the table client. @@ -159,6 +163,92 @@ To get the statistics of the account we call the GetStatistics method on the tab auto statistics = tableServiceClient.GetStatistics(); ``` +### Table Transactions Success + +In order to get the service properties we need to create a TableServiceClient first. + +```cpp +#include +... +using namespace Azure::Data::Tables; +... +auto tableServiceClient = TableServiceClient::CreateFromConnectionString(...); +``` + +We create a table on which we run the transaction and get a table client. +```cpp +// create table +tableServiceClient.CreateTable(TableName); +// get table client from table service client +auto tableClient = tableServiceClient.GetTableClient(TableName); +``` +N.B. Here we are obtaining the table client from the table service client using the credentials that were passed to the table service client. + +We initialize and populate the entities. +```cpp +Models::TableEntity entity1; +entity1.PartitionKey = "P1"; +entity1.RowKey = "R1"; +entity1.Properties["Name"] = "Azure"; +entity1.Properties["Product"] = "Tables"; + +Models::TableEntity entity2; +entity2.PartitionKey = "P2"; +entity2.RowKey = "R2"; +entity2.Properties["Name"] = "Azure"; +entity2.Properties["Product"] = "Tables"; +``` + +We create a transaction batch and add the operations to the transaction. +```cpp +// Create a transaction with two steps +std::vector steps; +steps.emplace_back(TransactionStep{TransactionActionType::Add, entity}); +steps.emplace_back(TransactionStep{TransactionActionType::Add, entity2}); +``` + +We then submit the transaction and check the response. +```cpp +// Check the response +if (!response.Value.Error.HasValue()) +{ + std::cout << "Transaction completed successfully." << std::endl; +} +else +{ + std::cout << "Transaction failed with error: " << response.Value.Error.Value().Message + << std::endl; +} +``` + +The output of this sample is: +```text +Transaction completed successfully. +``` + +### Table Transactions Error + +The difference from the previous example is that we are trying to add two entities with the same PartitionKey and RowKey. +```cpp +// Create two table entities +TableEntity entity; +TableEntity entity2; +entity.SetPartitionKey("P1"); +entity.SetRowKey("R1"); +... +entity2.SetPartitionKey("P1"); +entity2.SetRowKey("R1"); +... +``` + +The rest of the steps are the same as in the previous example. + +The output of the sample contains the error message: + +```text +Transaction failed with error: 1:The batch request contains multiple changes with same row key. An entity can appear only once in a batch request. +``` + ## Contributing See the [C++ Contributing Guide][sdk_contrib] for details on building, diff --git a/sdk/tables/azure-data-tables/samples/CMakeLists.txt b/sdk/tables/azure-data-tables/samples/CMakeLists.txt index ed7cdfba4..a9b7db734 100644 --- a/sdk/tables/azure-data-tables/samples/CMakeLists.txt +++ b/sdk/tables/azure-data-tables/samples/CMakeLists.txt @@ -18,3 +18,11 @@ create_per_service_target_build_for_sample(tables tables_entity_operations) add_executable(tables_service_operations tables_service_operations.cpp) target_link_libraries(tables_service_operations PRIVATE azure-data-tables get-env-helper) create_per_service_target_build_for_sample(tables tables_service_operations) + +add_executable(tables_transactions_ok tables_transactions_ok.cpp) +target_link_libraries(tables_transactions_ok PRIVATE azure-data-tables get-env-helper) +create_per_service_target_build_for_sample(tables tables_transactions_ok) + +add_executable(tables_transactions_fail tables_transactions_fail.cpp) +target_link_libraries(tables_transactions_fail PRIVATE azure-data-tables get-env-helper) +create_per_service_target_build_for_sample(tables tables_transactions_fail) diff --git a/sdk/tables/azure-data-tables/samples/README.md b/sdk/tables/azure-data-tables/samples/README.md index 9a0bf7484..fe7761a1f 100644 --- a/sdk/tables/azure-data-tables/samples/README.md +++ b/sdk/tables/azure-data-tables/samples/README.md @@ -14,3 +14,5 @@ description: Samples for the azure-data-tables client library. - Create,list and delete tables. - Create, merge, update, delete entities. - List Tables, Get Statistics, Get Access Policy for service. +- Submit Transactions success +- Submit Transactions failure diff --git a/sdk/tables/azure-data-tables/samples/tables_getting_started.cpp b/sdk/tables/azure-data-tables/samples/tables_getting_started.cpp index dc03a11f7..0cdf93765 100644 --- a/sdk/tables/azure-data-tables/samples/tables_getting_started.cpp +++ b/sdk/tables/azure-data-tables/samples/tables_getting_started.cpp @@ -30,7 +30,6 @@ const std::string TableName = "sample1"; int main() { auto tableServiceClient = TableServiceClient::CreateFromConnectionString(GetConnectionString()); - auto tableClient = TableClient::CreateFromConnectionString(GetConnectionString(), TableName); // create new table tableServiceClient.CreateTable(TableName); diff --git a/sdk/tables/azure-data-tables/samples/tables_transactions_fail.cpp b/sdk/tables/azure-data-tables/samples/tables_transactions_fail.cpp new file mode 100644 index 000000000..046c6fdb3 --- /dev/null +++ b/sdk/tables/azure-data-tables/samples/tables_transactions_fail.cpp @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include + +#include +#include +#include +#include + +using namespace Azure::Data::Tables; +using namespace Azure::Data::Tables::Models; + +const std::string TableName = "transactions2"; + +std::string GetConnectionString() +{ + const static std::string ConnectionString = ""; + + if (!ConnectionString.empty()) + { + return ConnectionString; + } + const static std::string envConnectionString = std::getenv("STANDARD_STORAGE_CONNECTION_STRING"); + if (!envConnectionString.empty()) + { + return envConnectionString; + } + throw std::runtime_error("Cannot find connection string."); +} + +int main() +{ + // Get the service client + auto tableServiceClient = TableServiceClient::CreateFromConnectionString(GetConnectionString()); + // create table + tableServiceClient.CreateTable(TableName); + // get table client from table service client + auto tableClient = tableServiceClient.GetTableClient(TableName); + + // Create two table entities + TableEntity entity; + TableEntity entity2; + entity.SetPartitionKey("P1"); + entity.SetRowKey("R1"); + entity.Properties["Name"] = TableEntityProperty("Azure"); + entity.Properties["Product"] = TableEntityProperty("Tables"); + entity2.SetPartitionKey("P1"); + entity2.SetRowKey("R1"); + entity2.Properties["Name"] = TableEntityProperty("Azure2"); + entity2.Properties["Product"] = TableEntityProperty("Tables2"); + + // Create a transaction with two steps + std::vector steps; + steps.emplace_back(TransactionStep{TransactionActionType::Add, entity}); + steps.emplace_back(TransactionStep{TransactionActionType::Add, entity2}); + + // Submit the transaction + auto response = tableClient.SubmitTransaction(steps); + + // Check the response + if (!response.Value.Error.HasValue()) + { + std::cout << "Transaction completed successfully." << std::endl; + } + else + { + std::cout << "Transaction failed with error: " << response.Value.Error.Value().Message + << std::endl; + } + // delete existing table + tableServiceClient.DeleteTable(TableName); + return 0; +} diff --git a/sdk/tables/azure-data-tables/samples/tables_transactions_ok.cpp b/sdk/tables/azure-data-tables/samples/tables_transactions_ok.cpp new file mode 100644 index 000000000..f8f0d97f2 --- /dev/null +++ b/sdk/tables/azure-data-tables/samples/tables_transactions_ok.cpp @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include + +#include +#include +#include +#include + +using namespace Azure::Data::Tables; +using namespace Azure::Data::Tables::Models; + +const std::string TableName = "transactions"; + +std::string GetConnectionString() +{ + const static std::string ConnectionString = ""; + + if (!ConnectionString.empty()) + { + return ConnectionString; + } + const static std::string envConnectionString = std::getenv("STANDARD_STORAGE_CONNECTION_STRING"); + if (!envConnectionString.empty()) + { + return envConnectionString; + } + throw std::runtime_error("Cannot find connection string."); +} + +int main() +{ + // Get the service client + auto tableServiceClient = TableServiceClient::CreateFromConnectionString(GetConnectionString()); + // create table + tableServiceClient.CreateTable(TableName); + // get table client from table service client + auto tableClient = tableServiceClient.GetTableClient(TableName); + + // Create two table entities + TableEntity entity; + TableEntity entity2; + entity.SetPartitionKey("P1"); + entity.SetRowKey("R1"); + entity.Properties["Name"] = TableEntityProperty("Azure"); + entity.Properties["Product"] = TableEntityProperty("Tables"); + entity2.SetPartitionKey("P1"); + entity2.SetRowKey("R2"); + entity2.Properties["Name"] = TableEntityProperty("Azure2"); + entity2.Properties["Product"] = TableEntityProperty("Tables2"); + + // Create a transaction with two steps + std::vector steps; + steps.emplace_back(TransactionStep{TransactionActionType::Add, entity}); + steps.emplace_back(TransactionStep{TransactionActionType::Add, entity2}); + + // Submit the transaction + auto response = tableClient.SubmitTransaction(steps); + + // Check the response + if (!response.Value.Error.HasValue()) + { + std::cout << "Transaction completed successfully." << std::endl; + } + else + { + std::cout << "Transaction failed with error: " << response.Value.Error.Value().Message + << std::endl; + } + // delete existing table + tableServiceClient.DeleteTable(TableName); + return 0; +}