DEV Community

loading...

C# - EF 5 with Cosmos DB: Multiple Entity Types in single Collection

kenakamu profile image Kenichiro Nakamura ・3 min read

The biggest difference between SQL Server and Cosmos DB, at least for me, is the ability to store different entity/document type in single collection. (of course depending on scenario)

In Distinguishing between different document types article, it gives us following sample.

Book documents:
{
    "id": "b1",
    "name": "Azure Cosmos DB 101",
    "bookId": "b1",
    "type": "book"
}

Review documents:
{
    "id": "r1",
    "content": "This book is awesome",
    "bookId": "b1",
    "type": "review"
},
{
    "id": "r2",
    "content": "Best book ever!",
    "bookId": "b1",
    "type": "review"
}
Enter fullscreen mode Exit fullscreen mode

Both document has:

  • id as unique key
  • bookId as good partition candidate
  • type to distinguish entity/document type/kind

In this article, I query these document by using EF 5.

Prerequisites

  • Cosmos DB Account
  • Basic C# knowledge

Create Console App

Let's see how we can query different entity type from single collection by using console app.

1. Create console app with .NET 5 and add Microsoft.EntityFrameworkCore.Cosmos NuGet package. I added version 5.0.5.

2. Add Models folder and add following models. I changed Review to have ReviewId and let Cosmos DB create Id.

public class Book
{
    public string Name { get; set; }
    public string BookId { get; set; }
    public string Type = nameof(Book);
}

public class Review
{
    public string ReviewId { get; set; }
    public string Content { get; set; }
    public string BookId { get; set; }
    public string Type = nameof(Review);
}
Enter fullscreen mode Exit fullscreen mode

3. Add CosmosContext.cs and paste following code.

  • It inherits from DbContext
  • In constructor, it delete existing database and create new one
  • It setup two DbSet. Books and Reviews
  • In OnConfiguring method, it reads connection string
public class CosmosContext : DbContext
{
    public CosmosContext()
        : base()
    {
        Database.EnsureDeleted();
        Database.EnsureCreated();
    }

    public DbSet<Book> Books { get; set; }
    public DbSet<Review> Reviews { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseCosmos("<your cosmos db connection string>");
    }
}
Enter fullscreen mode Exit fullscreen mode

4. Add following method in CosmosContext.cs. Here I build model. I use ToContainer to specify container name as name is different from default naming conventions. (books and reviews)
I also setup Partition Key, Discriminator and Key.

The Discriminator is the key to distinguish entity type.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Book>()
        .ToContainer("booksandreviews")
        .HasPartitionKey(x => x.BookId)
        .HasDiscriminator<string>(nameof(Book.Type));

    modelBuilder.Entity<Review>()
        .ToContainer("booksandreviews")
        .HasPartitionKey(x => x.BookId)
        .HasDiscriminator<string>(nameof(Review.Type));
    modelBuilder.Entity<Review>().HasKey(x => x.ReviewId);
}
Enter fullscreen mode Exit fullscreen mode

5. In Program.cs main method, add following code. I simply add three documents and query them by using DbSet.

static async Task Main(string[] args)
{
    var context = new CosmosContext();

    context.Add(new Book
    {
        Name = "Azure Cosmos DB 101",
        BookId = "b1"
    });

    context.Add(new Review
    {
        Content = "This book is awesome",
        BookId = "b1",
        ReviewId = "r1"
    });
    context.Add(new Review
    {
        Content = "Best book ever!",
        BookId = "b1",
        ReviewId = "r2"
    });

    await context.SaveChangesAsync();
    var books = await context.Books.ToListAsync();
    var reviews = await context.Reviews.ToListAsync();

    JsonConvert.DefaultSettings = () => new JsonSerializerSettings
    {
        Formatting = Formatting.Indented,
    };

    Console.WriteLine(JsonConvert.SerializeObject(books));
    Console.WriteLine(JsonConvert.SerializeObject(reviews));
}
Enter fullscreen mode Exit fullscreen mode

6. Run and see the result.

image

7. Query in Cosmos DB Explorer as well.

image

That's it! It's easy enough to use Entity Framework to query Cosmos DB (SQL API) even if I use multiple entity types in single collection :)

Reference

EF Core Azure Cosmos DB Provider

Discussion (0)

Forem Open with the Forem app