Entity Framework Core with Cosmos

Dan Cokely
6 min readNov 7, 2018

--

“stars overlooking body of water during nighttime” by Casey Horner on Unsplash

Update 11/19/2018

  • I’ve expanded on this intro article to walk through what a .NET Core API could look like running the EF Core Cosmos Provider, you check it out here

Intro

Microsoft's upcoming release of Entity Framework Core 2.2 has some cool features, including a preview Cosmos provider, allowing you to manage your Cosmos documents through EF Core (with caveats). While the full GA of the Cosmos provider may not be fully done before sometime in 2019, its still worth a look, and with the latest release getting close, it seemed like a good time to try out some of these features.

Quick Background

Entity Framework Core is Microsoft's ORM for managing data access by allowing developers to operate on classes representing business objects, instead of using T-SQL or similar to directly manage data in the database. EF Core is the cross platform rewrite of Microsoft’s traditional Entity Framework (now in EF 6). Using a provider like MS SQL Server you represent data objects as classes, with EF Core mapping your database tables and columns to these classes and properties (these classes are your Entities, and while technically the Entities should represent business objects, not DB tables, by design they often match your table structure, but a 1–1 mapping is not required). Through binding these Entities and building a Model, you can manage the data in the database tables using .NET code. This removes most of the need for custom SQL queries and manually managing inserts and selects, you can instead query using LINQ against the entity structures you define, and inserts become as simple as creating a new class and saving it to the database through EF Core.

Traditionally this functionality was mainly limited to relational providers ( aka SQL Server). This upcoming functionality in EF Core will allow first class support for the document based Cosmos DB (using the SQL API, which we’ll see later). This is great, as the documents in Cosmos are typically represented as classes anyway in your backend application. So now, adding a way to directly insert, read, etc. using EF Core will allow you to easily manage your documents without having to write your own data service layer to provide this same functionality (as is the main option now).

Demo

We’ll start out with setting up a Cosmos instance, then create a console app to write a document and then read it back using EF Core.

Starting from the Azure Portal we’ll create a Cosmos DB instance, you can create one from the top level “Create a resource” or the Cosmos DB section directly:

The important part of the Cosmos config is to use the SQL API for talking with Cosmos (we’ll still be dealing with documents, this is just the API we’ll use to talk with Cosmos).

Now with support of Cosmos being a preview feature, we’re not going to push our luck and enable Geo-Redundancy or Mult-region Writes, you will need to check the issue tracker on Github for the latest support/release issues HERE

You can review and create the instance, and let it provision. The next step is collecting the keys for communicating with the DB, we need the URI and PRIMARY KEY, which we’ll use later in the console app.

Next we’ll set up our Visual Studio project, for this example we’ll use a .NET Core Console App, but realistically this would be part of an API or Class Library project.

The next part is the NuGet packages, we need a few preview packages to make this work. Keep in mind these preview packages will change fairly frequently as they release updates, so these may be different, but install the following:

We only need two files to prove that our EF Core Cosmos setup is working. The first is a DbContext, which everyone who has used EF before will be familiar with:

We are first going to define one entity, TestDoc, which has three properties: Name, Email, and id. Id is automatically added to the Cosmos document, but it can be set by us, or can be created by Cosmos automatically. It is often useful to expose this identifier as a unique key to the document, so we’ll add it to the document ourselves. Since our EfTestContext class is so small, we’ll stick our entity definition (TestDoc) in the same file.

The other part of our class is the EF Core specific settings, starting with our DbSet TestDocs:

public DbSet<TestDoc> TestDocs { get; set; }

This exposes a DbSet of type TestDoc through the context, allowing us to take actions (create, read, etc.) on the collection of TestDoc entries in the DB.

This is an extremely simple example. We are not configuring OnModelCreating(…) and many of the other common EF configurations. We will go into more elaborate mappings later.

Next we are going to wire up our Main method. We have 2 methods, InsertDocAsync and FindDoc. In our Main we are going to create a new document with the name “FirstName LastName” and an email of “test@home.com”. We set the GUID of the id field on the client, but this can also happen on the Cosmos side. After we save the document, we are going to look it up by name, print it on the console window, then wait for user input to close.

For simplicity we just force the async calls to run from our Main() method, this is not a safe or efficient way to do this in a production setting, but for demonstration purposes it does the trick. Notice we create a new Cosmos document simply by creating a new TestDoc, adding it to our DbContext, then saving the changes back. Reading values out is just as simple, we can simply look documents up in our Context’s DbSet of TestDocs and filter out what we are looking for. Lets run the project and see what we get:

As you can see from above we got back the “FirstName LastName” from the document we just inserted. This means our round trip works!

Some interesting notes

Since we didn’t specify a collection for our documents, only a database name, Microsoft helpfully created one for us… named Unicorn

Its also important to note the line in our InsertDoc method:

await context.Database.EnsureCreatedAsync();

This will scaffold out what we need behind the scenes so we can just insert our docs. Typically you would have a more elaborate policy for creating a collection.

Wrap up

While the Cosmos provider is still in its infancy, you can begin to see the power in being able to represent your domain/business objects directly as Cosmos documents and using EF Core in between. Very little code is required to have a fully built out data model with CRUD support, essentially doing little more than defining your entities.

I’ll be following this up with another article, digging deeper into the setup of a more elaborate configuration, so stay tuned.

--

--