Introduction To Azure Cosmos DB Table API

This article will provide a short introduction to Database Systems and Azure Cosmos DB Table API with a code sample.

Azure Cosmos DB Table API
Azure Cosmos DB
 

Introduction

 
Azure Cosmos DB is a new globally distributed database. It can easily be scaled out (horizontally partitioning), and it is widely available around the world.
 
In this article series, I'll introduce Cosmos DB with code samples.
  • Table API
  • SQL API
  • API for MongoDB
  • Cassandra API
  • Gremlin API
Azure Cosmos DB is inspired by Dr. Leslie Lamport's theory. I want to thank Microsoft for their excellent choice and for the new fantastic Distributed Database System.
 
I highly recommend you watch Dr. Leslie Lamport's videos on YouTube and read about TLA+ and his contributions in Distributed Systems.
 
Before we begin, I want to make one thing very clear - Azure Cosmos DB is not to replace MS SQL Server. MS SQL Server is a Relational DBMS, and Cosmos DB provides native support for NoSQL, including Cassandra, MongoDB Gremlin, Spark, and SQL, etc. So, they are complementary to each other and not replacing each other.
 
As you can see in Figure 1, the relational databases are dominating from 1990 to 2000. The main problem was the old-style software architectures (Layered Architecture, Service-Oriented Architecture) with a relational database as a back-end is a vertical scalability/scaling up (fixed schema problem was less important). It was very expensive and sometimes hard to scale the application up. That was the main reason which helped ignite the NoSQL and Microservices revolution. Meanwhile, the image becomes more transparent, and as Martin Fowler has said, the polyglot persistence is the future for the database design.
 
Azure Cosmos DB Table API
Figure -1- Evaluation of Database Systems
 
Note
NewSQL is so important, like NoSQL, I recommend you read about it or to search for Michael Stonebraker on Google and YouTube.
 

What does it mean that Azure Cosmos DB primarily is NoSQL?

 
To answer the question, first, we have to know what is NoSQL.
 
NoSQL is a class of database management systems (DBMS), that does not follow all of the rules of a relational DBMS.
  • Not using the relational model
  • Running well on clusters
  • Mostly open-source
  • Schema-less
  • Different Data Models
The text mentioned above "Running well on clusters" is easy to say, but it is hard to apply. To understand the clusters problem, we have to understand the distributed computing and distributed data store. So, let us take a look into Eric Brewer CAP theorem.
 

CAP theorem

 
CAP stands for Consistency (C), Availability (A), and Partition Tolerance (P). When you design an application with a distributed database, then you must choose between those three guarantees and the theory said you could have a maximum of two choices from the three.
 
Azure Cosmos DB Table API
 
The CAP theorem demonstrates that any distributed system cannot guarantee C, A, and P at the same time; instead, there are always trade-offs between C, A, and P.
 
In the next post, I will write about the BASE Concept.
 

Cosmos DB

 
If you are comfortable with the CAP theorem, you will know that there are always trade-offs. Azure Cosmos DB has five consistency models so that you can decide for yourself what you deem most important and what you are willing to sacrifice.
 
The currently available consistencies are,
 
 
Strong
With strong consistency, you are always guaranteed to read the latest version of an item similar to reading committed isolation in SQL Server. You can only ever see data which is durably committed. Strong consistency is scoped to a single region.
 
Bounded-staleness
In bounded-staleness consistency, read will lag behind writes, and guarantees global order and is not scoped to a single region.
 
Session
Is the most popular consistency level, since it provides consistency guarantees, but also has better throughput.
 
Consistent Prefix
The global order is preserved, and the prefix order is guaranteed. A user will never see writes in a different order than that in which it was written.
 
Eventual
Is like asynchronous synchronization. It guarantees that all changes will be replicated eventually, and as such, it also has the lowest latency because it does not need to wait on any commits.
 

Cosmos Table API

 
Table API belongs to the key-value database with a schema-less design for rapid development and auto-scaling. Table API is based on structured NoSQL data stored in the cloud and is fitted for global distribution scenarios.
 
Scenarios to use Cosmos Table API
 
Users data, Devices, IoT, Structured Data. 
 
Azure Cosmos DB Table API
Figure -2- Key Value Database, in this case, Key is an integer, and the value is a sequence of bytes.
 

Table Structure

 
Account
Allows you to access Azure Cosmos DB and the Table API.
 
Table
Is a collection of entities. You can compare it just like a table in the relational database.
 
Entities
An entity is a set of properties, similar to the row of the relational database.
 
Properties
A property is a name-value pair. It is like a dictionary; the property name is the dictionary key. Each entity has three system properties that specify a partition key, a row key, and a timestamp.
 

Features

  • No limits on numbers of tables, rows or a table size
  • Dynamic load balancing
  • NoSQL- Schema-less entities with strong Consistency
  • Best for key/Value lookups on partition key and row key
  • Entity group transaction for atomic batching.
  • Guaranteed high availability.
  • Automatic secondary indexing.

Entity Group Transaction

 
Groups the entity changes in a batch operation, then commits the changes together. Either all changes will be committed successfully, or all will fail. This operation can be executed under one condition: The entities must belong to the same partition; I have demonstrated below with a code sample.
 

Concurrencies

 
Pessimistic Concurrency
Locking the Entity so one call can write and blocking the other calls until the writing process is finished.
 
Optimistic Concurrency
The caller receives a notification about the concurrency changes in the entity, and he can decide which behavior is correct. Optimistic Concurrency is the default Azure one. I have simulated the Optimistic Concurrency problem below in the code sample.
 
Last write wins
However, write the data last that goes in the most current row.
 

Cosmos API Code Sample

 
Pre-Installation
 
As I said before, each entity has a partition key and row key. Partition Index and the row Index are used to create the clustered index, so please choose them carefully. Those keys are the glue for good design and excellent performance, and I highly recommend you to follow Microsoft design guidelines.
 
Entities with the same partition are put in a single tablet server, and the row key is used to identify the entity itself in the same partition.
 
I have defined a domain entity object “User” which need to be persisted.
  1. public class User : TableEntity  
  2. {  
  3.     public string EMail { getset; }  
  4.   
  5.     public DateTimeOffset LastLogin { getset; }  
  6.   
  7.     public User()  
  8.     {  
  9.     }  
  10.   
  11.     public User(string locationId, string type)  
  12.     {  
  13.       PartitionKey = locationId;  
  14.       RowKey = type;  
  15.     }  
  16. }  
LocationId and the user type --  I have used them for the partition key and row key.
 
The database context.
 
I have added a database context class which used to create a cloud account from the connection string and creating/retrieving the users' cloud table. 
  1. public class CosmosTableApiDbContext  
  2. {  
  3.     public CloudStorageAccount CreateCloudStorageAccount(string connectionString)  
  4.     {  
  5.       return CloudStorageAccount.Parse(connectionString);  
  6.     }  
  7.   
  8.     public CloudTable GetTableClient(string tableName, CloudStorageAccount storageAccount)  
  9.     {  
  10.       var tableClient = storageAccount.CreateCloudTableClient();  
  11.   
  12.       var table = tableClient.GetTableReference(tableName);  
  13.   
  14.       // Create the cloud table client to interacting with the table service   
  15.       if (table.CreateIfNotExists())  
  16.       {  
  17.         Console.WriteLine("Created Table named: {0}", tableName);  
  18.       }  
  19.       else  
  20.       {  
  21.         Console.WriteLine("Table {0} already exists", tableName);  
  22.       }  
  23.       return table;  
  24.     }  
  25. }  
The connection string. 
  1. <appSettings>  
  2.     <!--  Azure Cloud Cosmos DB -->  
  3.     <add key="cloud:StorageConnectionString" value="..." />  
  4.     <add key="cloud:Tablename" value="…" />  
  5.     <add key="cloud:TableThroughput" value="400" />  
  6.     <!-- Local Emulator -->  
  7.     <add key="emulator:StorageConnectionString" value="DefaultEndpointsProtocol=https;AccountName=MyFirstCosmosDB;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==;TableEndpoint=https://localhost:8081/;" />  
  8.     <add key="emulator:Tablename" value="Users" />  
  9.     <add key="emulator:TableThroughput" value="400" />  
  10. </appSettings>  
I have modified the App.config, as shown above.
 
I have copied the key from the emulator, as shown below.
 
Azure Cosmos DB Table API
 
The CRUD Operations
 
I have added a demo class for the very basic CRUD operations,
  1. public void CrudOperations(CloudTable cloudTable)  
  2. {  
  3.       // Create a user.  
  4.       var user = new User("Karlsbad""Admin")  
  5.       {  
  6.         EMail = "alugili@gmail.com",  
  7.         LastLogin = DateTimeOffset.UtcNow  
  8.       };  
  9.   
  10.       Console.WriteLine("******************** Create a user ********************");  
  11.   
  12.       // Create the insert replace operation.  
  13.       var insertOrReplaceOperation = TableOperation.InsertOrReplace(user);  
  14.   
  15.       // Execute the operation. I have ignored the result just for demo.  
  16.       _ = cloudTable.Execute(insertOrReplaceOperation);  
  17.   
  18.       Console.WriteLine($"user is created {user.ETag}");  
  19.   
  20.       // In the Production Code! You can evaluate the result to check that the operation has successfully finished!  
  21.   
  22.       Console.WriteLine("******************** Update a user ********************");  
  23.       // Create the insert merge operation.  
  24.       var insertOrMergeOperation = TableOperation.InsertOrMerge(user);  
  25.   
  26.       user.EMail = "bassam.alugili@hotmail.de";  
  27.   
  28.       _ = cloudTable.Execute(insertOrMergeOperation);  
  29.   
  30.       Console.WriteLine($"user is updated {user.ETag}");  
  31.   
  32.       Console.WriteLine("******************** Find a user ********************");  
  33.       // Create the retrieve operation.  
  34.       var retrieveOperation = TableOperation.Retrieve<User>("Karlsbad""Admin");  
  35.   
  36.       // Find the entity with PartitionKey ="Karlsbad" and RowKey="Admin"  
  37.       var retrieveResult = cloudTable.Execute(retrieveOperation).Result;  
  38.   
  39.       var retrievedUser = retrieveResult as User;  
  40.   
  41.       Console.WriteLine($"user is found {retrievedUser?.ETag}");  
  42.   
  43.       Debug.Assert(retrievedUser?.EMail == "bassam.alugili@hotmail.de");  
  44.   
  45.       Console.WriteLine("******************** Delete a user ********************");  
  46.   
  47.       // Delete the retrieve user.  
  48.       var deleteOperation = TableOperation.Delete(retrievedUser);  
  49.       _ = cloudTable.Execute(deleteOperation);  
  50.       Console.WriteLine($"user is deleted {retrievedUser.ETag}");  
  51. }  
I have started the demos as below,
  1. public class Program  
  2. {  
  3.     public static void Main(string[] args)  
  4.     {  
  5.       //const string enviromentName = "cloud";  
  6.       const string enviromentName = "emulator";  
  7.   
  8.       var connectionString = ConfigurationManager.AppSettings[$"{enviromentName}:StorageConnectionString"];  
  9.       var tableName = ConfigurationManager.AppSettings[$"{enviromentName}:TableName"];  
  10.   
  11.       var azureTableContext = new CosmosTableApiDbContext();  
  12.       var sa = azureTableContext.CreateCloudStorageAccount(connectionString);  
  13.       var cloudTable = azureTableContext.GetTableClient(tableName, sa);  
  14.   
  15.       Console.WriteLine("Starting Demos!");  
  16.   
  17.       // Demo for the basic CRUD operations.  
  18.       var crudOperationsSample = new CrudOperationsSample();  
  19.       crudOperationsSample.CrudOperations(cloudTable);  
  20.   
  21.       // Demo for the batch operation.  
  22.       var batchOperationSample = new BatchOperationSample();  
  23.       batchOperationSample.BatchOperation(cloudTable);  
  24.   
  25.       // Demo for the default Pessimistic Concurrency.  
  26.       var pessimisticConcurrency = new ConcurrencyDemo();  
  27.       pessimisticConcurrency.ConcurrencyDemoDefaultPessimistic(cloudTable);  
  28.   
  29.       Console.WriteLine("Done!");  
  30.       Console.ReadKey();  
  31.     }  
  32. }  
Here is the result for the CRUD Operations demo,
 
Azure Cosmos DB Table API
 
So, let us do it step by step and see the results,
  1. // Create the insert replace operation.  
  2. var insertOrReplaceOperation = TableOperation.InsertOrReplace(user);  
  3.   
  4. // Execute the operation. I have ignored the result just for demo.  
  5. _ = cloudTable.Execute(insertOrReplaceOperation);  
  6.   
  7. Console.WriteLine($"user is created {user.ETag}");  
I have opened the Azure Cosmos DB Emulator Explorer Window to see the data as shown below,
 
Azure Cosmos DB Table API
 
As you see, the user is created and added.
 
Then the second code part,
  1. Console.WriteLine("******************** Update a user ********************");  
  2. // Create the insert merge operation.  
  3. var insertOrMergeOperation = TableOperation.InsertOrMerge(user);  
  4.   
  5. user.EMail = "bassam.alugili@hotmail.de";  
  6.   
  7. _ = cloudTable.Execute(insertOrMergeOperation);  
When I refresh the query on the emulator then, EMail is changed.
 
Azure Cosmos DB Table API
 
Finally, the code below will remove the created user.
  1. // Delete the retrieved user.  
  2. var deleteOperation = TableOperation.Delete(retrievedUser);  
  3. _ = cloudTable.Execute(deleteOperation);  
Azure Cosmos DB Table API
 
Batch Operation Example
  1. public class BatchOperationSample  
  2. {  
  3.     public void BatchOperation(CloudTable cloudTable)  
  4.     {  
  5.       Console.WriteLine("******************** Start Batch Operation ********************");  
  6.       var batchOperation = new TableBatchOperation();  
  7.       for (var i = 2; i < 52; i++)  
  8.       {  
  9.         // I will create and add users and send them as one batch to the table.  
  10.         var batchUser = new User("Karlsbad""Admin_" + i)  
  11.         {  
  12.           EMail = "alugili@gmail.com",  
  13.           LastLogin = DateTimeOffset.UtcNow  
  14.         };  
  15.   
  16.         batchOperation.Add(TableOperation.InsertOrMerge(batchUser));  
  17.       }  
  18.   
  19.       // Executing the operations or adding the users.  
  20.       cloudTable.ExecuteBatch(batchOperation);  
  21.       Console.WriteLine("******************** End Batch Operation ********************");  
  22.   
  23.     }  
  24. }  
Emulator
 
Azure Cosmos DB Table API
 

Pessimistic Concurrency Demo

 
In the code below,
  1. I have created the firstUser and checked it in.
  2. Simulating that the third party has changed the created first user “updatedFirstUser”
  3. Finally, I have tried to change the firstUser and checking in the changes
  4. BOOM! Concurrency Exception! 
  1. public void ConcurrencyDemoDefaultPessimistic(CloudTable cloudTable)  
  2. {  
  3.       Console.WriteLine("**************************** Start Demonstrate pessimistic concurrency ****************************");  
  4.   
  5.       // Add new user to table.  
  6.       var firstUser = new User("Karlsruhe""Operator")  
  7.       {  
  8.         EMail = "alugili@gmail.com",  
  9.         LastLogin = DateTimeOffset.UtcNow  
  10.       };  
  11.   
  12.       var insertOrReplaceOperation = TableOperation.InsertOrReplace(firstUser);  
  13.       cloudTable.Execute(insertOrReplaceOperation);  
  14.       Console.WriteLine("Entity added. Original ETag = {0}", firstUser.ETag);  
  15.   
  16.       // Someone else has changed the first user!  
  17.       var updatedFirstUser = new User("Karlsruhe""Operator")  
  18.       {  
  19.         EMail = "bassam.alugili@hotmail.de",  
  20.         LastLogin = DateTimeOffset.UtcNow  
  21.       };  
  22.   
  23.       insertOrReplaceOperation = TableOperation.InsertOrReplace(updatedFirstUser);  
  24.       cloudTable.Execute(insertOrReplaceOperation);  
  25.       Console.WriteLine("Entity updated. Updated ETag = {0}", updatedFirstUser.ETag);  
  26.   
  27.       // Try updating first user. Etag is cached within firstUser and passed by default  
  28.       firstUser.LastLogin = DateTimeOffset.UtcNow;  
  29.   
  30.       insertOrReplaceOperation = TableOperation.Merge(firstUser);  
  31.       try  
  32.       {  
  33.         Console.WriteLine("Trying to update Original entity");  
  34.         cloudTable.Execute(insertOrReplaceOperation);  
  35.       }  
  36.       catch (StorageException ex)  
  37.       {  
  38.         if (ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.PreconditionFailed)  
  39.         {  
  40.           Console.WriteLine("Error: Entity Tag is changed!");  
  41.         }  
  42.         else  
  43.         {  
  44.           throw;  
  45.         }  
  46.       }  
  47.       Console.WriteLine("**************************** End Demonstrate pessimistic concurrency ****************************");  
  48. }  
Exception
 
Azure Cosmos DB Table API

Summary

 
You have read a small introduction to database systems and Azure Cosmos DB. I hope you have understood what the CAP theory is and why we need it. Also, you have read about Azure Cosmos DB Table API with code Samples for CRUD, Batch, and Concurrency. Now, you can create an Azure Cosmos DB Table API database with Cosmos DB emulator. In the next article, I will write about the SQL API. Thank you for reading my article, and I hope you have enjoyed the reading as much as I have enjoyed the writing. You can follow me on C# Corner/Twitter or my webpage.