Skip to content

Using Cosmos DB databases

Jon P Smith edited this page Nov 9, 2021 · 3 revisions

Setting up Cosmos DB options linked to Azure Cosmos DB Emulator

If you are testing Cosmos DB, then the Azure Cosmos DB Emulator is a great tool to use. It runs locally on the development system and allows you to test Cosmos DB queries without paying for a Cosmos DB database on Azure.

Here is an example of using the CreateUniqueClassCosmosDbEmulator<T> method, which takes the class as the name of the database.

public async Task TestAddCosmosBookWithReviewsOk()
{
    //SETUP
    var options = this.CreateUniqueClassCosmosDbEmulator<CosmosDbContext>();
    using var context = new CosmosDbContext(options);
    await context.Database.EnsureDeletedAsync();
    await context.Database.EnsureCreatedAsync();

    //ATTEMPT
    var cBook = new CosmosBook
    {
        CosmosBookId = 1,
        Title = "Book Title",
        PublishedDate = new DateTime(2019, 1,1),
    };
    context.Add(cBook);
    await context.SaveChangesAsync();

    //VERIFY
    await context.Books.FindAsync(1).ShouldNotBeNull();
}

_NOTE: Cosmos DB only provides async methods to access its database so you must use EF Core async methods, otherwise you may have some problems - see EF Core Cosmos DB limitations.

Ability to add extra options to the DbContextOptionsBuilder<T>

All the previous extension methods have an optional parameter that allows you to set extra options at the DbContextOptionsBuilder<T> level. Below is part of the unit tests showing how to add/override options.

//... previous code removed to focus on the feature
var options = this.CreateUniqueClassCosmosDbEmulator<BookContext>(
    builder => builder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)); //sets a tracking behavior
using (var context = new BookContext(options))
{
    //VERIFY
    var book = context.Books.First();
    context.Entry(book).State.ShouldEqual(EntityState.Detached);
}

The CreateUniqueMethodOptions() extension method

This returns a Cosmos DB options with the connection string from the appsettings.json file but the name of the database now has the type name of the object (which should be this) followed by the method name as a suffix. See test code below

[Fact]
public void TestSqlServerUniqueMethodOk()
{
    var options = this.CreateUniqueMethodCosmosDbEmulator<EfCoreContext>();
    using var context = new EfCoreContext(options))
    
    //... other parts left out   
}

NOTE: You shouldn't really need the CreateUniqueMethodOptions<T> method, as xUnit runs the methods inside a test class serially, so CreateUniqueClassOptions<T> should be enough to avoid parallel unit tests accessing the same database.

Obtaining EF Core logging data

Its often useful to see what EF Core is doing when something isn't working properly. The `CreateUniqueMethodCosmosDbEmulatorWithLogTo method returns the logs. Below is a simple version that captures the logs into a list, but more complex options are possible - see Tools for capturing EF Core logging for more details.

var logs = new List<string>();
var options = this.CreateUniqueMethodCosmosDbEmulatorWithLogTo<BookContext>(log => logs.Add(log));
using var context = new BookContext(options);
//... rest of test left out

How to get an empty database with the correct schema

Cosmos DB database are quick to create / delete because they don't have relationships etc., so best way (and only way) is to call EnsureDeletedAsync followed by EnsureCreatedAsync - see the code below

var options = this.CreateUniqueClassCosmosDbEmulator<CosmosDbContext>();
using var context = new CosmosDbContext(options);
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
Clone this wiki locally