The purpose of the code in this repository is to help people get up-to-speed with the .Net CosmosDB SDK and interacting with CosmosDB thru C#. This is part of a broader curriculum to help onboard new developers who are not familiar with CosmosDB.
All developers are encouraged to review the following two videos before starting:
The next two labs in this section help to introduce team members to CosmosDB, including storing multiple different types of documents in a collection, making raw SQL queries within the collection, using projections, and getting started with stored procedures.
Azure CosmosDB Hands-On Labs from aliuy The purpose of this first lab is to get you familiar with the query capabilities of CosmosDB and write your first stored procedure that modifies existing records. Supplemental Documentation: How to query using SQL?
Microsoft Azure Code Challenges - CosmosDB Lab The purpose of this second lab is to get users exposed to an existing project already using the CosmosDB SDK from .Net. They will get to tinker with the C# project and add a command to query, then understand what's happening under the hood when executing different queries. Supplemental Documentation: Develop with the DocumentDB API in .NET
The purpose of this lab is to deepen the knowledge gained from the above pre-requisites and provide more direct hands-on experience with the CosmosDB SDK.
At the end of this lab, developers should feel comfortable using the CosmosDB SDK to:
- Initialize a connection to CosmosDB.
- Initialize a database and collection within CosmosDB.
- Create queries to get one or more documents from CosmosDB.
- Create commands to insert and update documents in CosmosDB.
The basic data structure we're working with in this lab is a Trial Balance. Upon cloning the repository, the Trial Balance looks as follows:
{
"Id": "Guid",
"FirmGuid", "Guid",
"EngagementName": "string"
}
We will setup a new database and collection (if it doesn't exist), followed by setting up the commands to insert and update our existing records, our queries to retrieve data from cosmosdb, then enhancing our queries to allow for pagination.
At the end of this scenario, you should have initialized a connection to CosmosDB, intialized the database and collection, and finally, retrieved all documents from the collection.
- Clone this repository and open the solution in Visual Studio.
- Start up the console application by using
F5
and familiarize yourself with the actions available. - Open the
InitializeDocumentDb
class and implement the CosmosDB-specific logic to initialize a connection to CosmosDB. - In the same class, implement the logic necessary to initialize a database named
chrislabz
and a collection namedtrialbalances
. - Open the
GetAllTrialBalances
class and implement the CosmosDB-specific logic to get all records from thetrialbalances
collection. - Run the console application and make sure you can get all TrialBalances. Initially, you should get no records. Use the CosmosDB Migration Tool to import the following JSON: trialbalances.json
At the end of this scenario, you should be able to retrieve a specific document based on Guid. As a stretch goal, you will also implement a query to retrieve all TrialBalances that match a particular string input by the user.
- Open the
GetSpecificTrialBalance
class and implement CosmosDB-specific logic to get a single record from thetrialbalances
collection based on Guid. - Start the console application and get all TrialBalances. Copy the ID of one of the TrialBalances.
- Execute the flow to
Get a specific record by id
and use the ID you just copied to retrieve the record. You should see the record was retrieved successfully and see the Engagement Name. - Stop the console application and go to the
SearchTrialBalances
class. Implement the CosmosDB-specific logic to search for TrialBalances by name. You want to do a case-insensitive wildcard match based on the name. - Start the console application and execute the flow to search for TrialBalances. You should see all TrialBalances retrieved that contain the searched name.
At the end of this scenario, you should be able to create new TrialBalance records in your trialbalances
collection. Additionally, you'll learn how the default property names serialize to JSON, and how to specify custom property names in the documents. As a stretch, try to modify the POCO that describes a TrialBalance, add new properties, and ensure new records are created with those properties to see how those properties show up in CosmosDB.
- Open the
CreateTrialBalance
class and implement the CosmosDB-specific logic to create a single record in thetrialbalances
collection. - Start up the console application and create a new TrialBalance. Get all the TrialBalances and see that your record was creaetd succesfully!
- Close the console application and go to
Program.cs
. Go to line 53 (where theTODO
is located) and comment out the line. - Start up the console application and create a new TrialBalance. Then, attempt to retrieve the document with the created ID.
- You'll notice that if you use the returned ID for the record upon creation, the query does not return the requested TrialBalance.
- Open DocumentDB studio (or the Query Explorer thru the Portal). Execute the following query (replacing
<New ID>
with the guid returned earlier):
SELECT * FROM c WHERE c.id = '<New ID>'
You will notice the following anomaly in the record:
{
"id": "<guid>",
"Id": "<New ID>
}
CosmosDB by default will auto-generate an id
for a document when one is not specified. However, your query is likely setup to be based on the Id
column that's now shown in CosmosDB. The simplest fix: ensure that the Id
column is mapped to the id
column:
- Open the
TrialBalance
class. Use theJsonProperty
attribute to change thePropertName
toid
. - Start up the console application and try step 4 again. If it succeeds, great! Do it once again, and you'll notice it fails. Why is this?
If you've uncommented the code properly in step 3, what we've now introduced is a serialization of the id
property in all cases, including when no Guid
is specified against the id
. The first time you create a document without specifying the id
, this uses default(Guid)
which is the same as Guid.Empty
. The second time, it uses the same default(guid)
, but you cannot create multiple documents with the same id
.
- Open the
TrialBalance
class again. Use theJsonProperty
attribute to ensure that null or default values are ignored during serialization. - Repeat step 8 again. This time, multiple document creations should succeed.
By this point, you should be pretty comfortable working with the SDK and interacting with CosmosDB. At this point, you'll flush out your knowledge by implementing update capabilities.
- Open the
UpdateTrialBalance
class and implement CosmosDB-specific logic to update an existing record. You should throw anArgumentException
if the requested TrialBalance does not exist. - Run the console application and verify you can update an existing TrialBalance Engagement Name.
- Modify the
UpdateTrialBalanceArgs
class and add anETag
property. UseJsonIgnore
to ensure the property is not serialized. - Modify
UpdateTrialBalance
and add options to the query to eforceETag
checks. Modify the console application to allow theETag
to be specified, and if so, force the check. Force a situation where you can get aPreconditionsFailed
(e.g. theETag
is old).