Azure Cosmos DB - SQL API Using EF Core

Introduction

 
In my previous article, we have seen the introduction of the Cosmos DB. If you haven’t read my previous article, then I highly encourage you to do so here.
 

Azure Cosmos DB CLI

 
Let’s begin with creating Azure resources using CLI
  1. //login  
  2. az login  
  3.    
  4. //Resource group creation  
  5. $resourcegroup="CosmosDBverify"  
  6. az group create -l southindia -n $resourcegroup  
  7.    
  8. //Cosmos DB Account creation  
  9. $name="cosmosverify"  
  10. az cosmosdb create -n $name -g $resourcegroup --default-consistency-level Session   
  11.    
  12. //Cosmosdb creation  
  13. az cosmosdb sql database create -a $name -n $name -g $resourcegroup --throughput 400   
First, after running AZ login, CLI will open your default browser and load an Azure sign-in page. Afterward, the user has to sign-in.
 
In the second part, we are creating a resource group with the name “CosmosDBVerify” by running the below script:
  1. $resourcegroup="CosmosDBverify"  
  2. az group create -l southindia -n $resourcegroup  
Next, we are creating the Cosmos DB account by using the below script:
  1. $name="cosmosverify"  
  2. az cosmosdb create -n $name -g $resourcegroup --default-consistency-level Session  
Lastly, we are creating SQL Cosmos DB using the following:
  1. az cosmosdb sql database create -a $name -n $name -g $resourcegroup --throughput 400   
Here, I want to be more specific about throughput, so setting it to 400 RU. The default value of throughput is 400 RU.
 
Note
As of today(July 5th, 2020), Microsoft is providing free Cosmos DB account for preview. You can utilize that as well by going directly here.
 

Coding

 
In this article, I’m using a classic example of maintaining a user/employee profile such as information about his current company, previous companies, etc.
 
Without wasting much time, let’s begin by creating a .net core console application. Firstly, add Microsoft.EntityFrameworkCore.Cosmos NuGet package.
 
Let's create an entity class:
  1. public class Profile  
  2.     {   
  3.         public string Title { getset; }  
  4.         public string FirstName { getset; }  
  5.         public string LastName { getset; }  
  6.         public string DOB { getset; }  
  7.         public string PhoneNumber { getset; }  
  8.         public string Designation { getset; }  
  9.         public Company CurrentCompany { getset; }  
  10.         public string HighestEducation { getset; }  
  11.         public ICollection<Company> PreviousCompanies { getset; }  
  12.         public string UserId { get;  set; }  
  13. }  
  1. public class Company  
  2.     {  
  3.         public string CompanyName { getset; }  
  4.         public DateTime StartDate { getset; }  
  5.         public DateTime EndDate { getset; }  
  6.         public bool IsActive { getset; }  
  7.     }  
Instead of using Data Annotations, I would like to use Fluent API for certain reasons:
  • Data Annotation violates the Separation of the Concerns principle and the couple's persistence layer with domain model logic.
  • Fluent API decouples my models from Entity Framework.
  • It provides more options for configurations than Data Annotation attributes.
Now, we can configure the mappings between these two entities by using IEntityTypeConfiguration<T> interface as follows:
  1. public class ProfileEntityConfiguration:IEntityTypeConfiguration<Profile>  
  2.     {   
  3.         public void Configure(EntityTypeBuilder<Profile> builder)  
  4.         {  
  5.             builder.HasKey(x => x.UserId);  
  6.             builder.HasPartitionKey(x => x.UserId);  
  7.             builder.OwnsOne(x => x.CurrentCompany);  
  8.             builder.OwnsMany(x => x.PreviousCompanies);  
  9.                
  10.         }  
  11.     }  
 Methods  Description
HasKey  It is used to denote the property that uniquely identifies an entity. This is mainly the Primary key of the table.
HasPartitionKey   It is used to store the partition key. In my example, I have used UserId as the partition key
OwnsOne  It is used to define one-one mapping between tables.
OwnsMany  It is used to define one-many mappings between tables
 
After creating that class with the necessary customizations, you need to wire that up to your DbContext’s OnModelCreating method by calling modelBuilder.ApplyConfiguration(new ConfigClass()).
  1. public class ProfileContext:DbContext  
  2.     {  
  3.         public DbSet<Profile> Profiles { getset; }  
  4.    
  5.         protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)  
  6.         {     
  7.             var accountEndpoint = "";  
  8.             var accountKey = "";  
  9.             var dbName = "";  
  10.             optionsBuilder.UseCosmos(accountEndpoint, accountKey, dbName);  
  11.         }  
  12.    
  13.         protected override void OnModelCreating(ModelBuilder modelBuilder)  
  14.         {  
  15.             modelBuilder.ApplyConfiguration(new ProfileEntityConfiguration());  
  16.         }  
  17.     }  
Now writing our required logic in the main method:
  1. static void Main(string[] args)  
  2.         {  
  3.             var context = new ProfileContext();  
  4.             context.Database.EnsureCreated();  
  5.             context.Profiles.Add(new Profile  
  6.             {  
  7.                 UserId = Guid.NewGuid().ToString(),  
  8.                 CurrentCompany = new Company  
  9.                 {  
  10.                     CompanyName = "Infosys",  
  11.                     StartDate = DateTime.Today,  
  12.                     IsActive = true  
  13.                 },  
  14.                 PreviousCompanies=new List<Company>  
  15.                 {  
  16.                     new Company  
  17.                     {  
  18.                         CompanyName="Wipro",  
  19.                         StartDate=DateTime.Today.AddYears(-7),  
  20.                         IsActive=false  
  21.                     }  
  22.                 }  
  23.             });  
  24.             context.SaveChanges();  
  25.             Console.ReadLine();  
  26.         }  
To keep it simple, I have directly used DbContext in the main program, but I would highly recommend you implement a repository pattern.
 
Note
Ef Core doesn’t support migration for Cosmos DB. In the above main function, I have used context.Database.EnsureCreated() to ensure whether the Cosmos DB is in sync with the entity classes.
 
In the next article, we’ll look into Geo-replication by using this example in the .NET core API.
 
I hope you liked the article. In case you found the article interesting, then kindly like and share it.