In this post I'll be taking a first look at the new (unreleased) Cosmos DB SQL Provider for Entity Framework Core, getting it up and running in an Azure Functions V2 project with the awesome Function Monkey library.

In the previous post we looked at getting the new Cosmos DB provider for EF Core up and running with a single entity, inside an ASP.NET Core application.

I've been working quite a bit with Azure Functions recently and I've been loving them so far. I've found Function Monkey to be an excellent library for working with them - which, as the author states, allows you to:

Use a clean fluent API to create functions with all the boilerplate taken care of and runtime support for authorization and dependency injection.

You can find more information, including a walkthrough here.

I'll cover setting up a new project using Function Monkey, adding in the new EF Core Cosmos DB provider, and then we'll play around with related entities.

To start with, make sure you've got everything you need to get this working - see this page for details of what you need for Azure Functions, and you've also built the EFCore Cosmos SQL project (see previous post if not).

I'll start by creating a new empty V2 Function project.



And this is the (very) empty Function project.


You can use Nuget to add our packages, or just copy and paste the package list below into your csproj file:


Note - You'll also need to add a reference to the EfCore.Cosmos.Sql project. I have also set the EF version to 2.1.0 rather than 2.1.1 - the newer version seems to have compatibility issues with Azure Functions V2 at this time.

Once that's done, I've created two new classes - FunctionAppConfiguration, which holds the configuration details for the functions, and an AutoMapperProfile class. I'll leave these both blank for now.

I've also copied in the Entities folder from the previous Web API project, changed the namespace in the files, and added in a second entity called (rather imaginatively) TestEntity2. Ive also created a navigation property to this entity on our TestEntity1.

Function Monkey uses commands and command handlers, so I'm creating two folders to hold these in.

Let's see some screenshots.

Project files:






Now, we need some commands and corresponding command handlers. I'm going to keep this simple, so we'll just create two commands which will map to two functions - CreateTestEntity1Command & GetTestEntity1Command. We'll return a string with the ID from the Create function, and the full entity POCO from the Get function. I'd normally create Response classes (essentially ViewModels/DTO's) for the responses rather than return full POCO's.

Here they are - our Get command has an ID property and returns a TestEntity1 POCO, and our Create command has a Name and Description property and returns a string.



Now we need the handlers. This is the basic boilerplate needed for a new handler:


We pass in the DbContext via the constructor, create a new entity and save it, before passing back the generated ID.


And the Get handler:


Looking good! Now, In order to have the DbContext available for injection, we need to setup the main FunctionAppConfiguration class. I love how all of this is setup & configured in Function Monkey.


There are a few things going on in this screenshot, and if you're unfamiliar with Function Monkey I would recommend following the getting started guide first. I've added the DbContext in exactly the same way as we did in the Web API project. Further down I've registered the two functions and the corresponding commands, with the GetTestEntity1Command having the route parameter {id}. The functions are both anonymous only, but it's very easy to add JWT token validation.

Now we can debug:


A quick test of the Get function using Postman:


And a quick test of the Create function:


With the corresponding entity in Cosmos DB:


Now, interestingly it hasn't included the navigation property for TestEntity2 at all in the saved document, not even as let's explore this a bit more.

I'm writing this post with the benefit of hindsight, but it took a bit of trial and error to figure out entity relations. I'm sure the way I'm doing things here isn't necessarily correct or the only way to do it, so I'll provide updates as I figure this out further.

At first I thought I'd see if I could use complex types, storing relating entities inside a single document in Cosmos Db. I experimented with both the [Owned] attribute and with the Fluent API but neither worked. In the end I had to have an id on the related entity (otherwise it threw an error saying a key needed to be defined) & add the entity into the DbContext. This is how my DbContext looks with both TestEntity1 & 2 setup:


Let's go back to our Create handler and set it to create the second entity. A bit of a contrived example, I know...forgive me.


Testing generated an id...and we can see this in the Cosmos Db Explorer:


We've got our navigation property, with an ID! Which corresponds to the related entity record in Cosmos DB:


Pretty awesome. You can see the 'Discriminator' property is set to the different entity names. Now let's fetch the parent entity via our Get command:


But our navigation property is still null. Hmm, but I'm not using EF Proxies...I guess that's just how it works, at least right now, so let's explicitly include it in our context call. However, we can't use 'Include' with the 'Find' command. So, we can test this out by using Where, to start with - as below:

2018-08-13-17_43_01-Window works!


Just for sake of completeness, we can also revert back to the Find method, and then manually load the property as well, as below:


So, to finish off, how about a collection of related entities. Here's our revised TestEntity1:


And our updated create handler:


And after we post the entity, our Cosmos DB documents:

2018-08-13-17_52_02-Window no collection of Id's in the TestEntity1 document for the collection. What about on one of the collection documents?


Nice, we've got a new property - 'TestEntity1id' - referring back to the parent entity. Now we manually load the collection property in our Get handler, like so:


And in Postman we now get back our parent entity with all of the related entities included:



I'll be continuing to experiment with this and I'll update or create new posts with my findings.

And yes, I forgot to use AutoMapper in this example, so the code to include it was completely unnecessary. I'll create a new post on using this in the future...