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"
}
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);
}
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>");
}
}
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);
}
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));
}
6. Run and see the result.
7. Query in Cosmos DB Explorer as well.
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 :)
Top comments (2)
You might want to consider not using BookId as your partition key.
learn.microsoft.com/en-us/azure/co...
There is a video on that page that explains as well. Ideally you want something that is a constant value that doesn't change. You also want something that if you divided all your documents into separate stacks based on your partition key, you would have roughly equal stack sizes.
You are absolutely right. We need to carefully think about partition key strategy! Thanks for pointing out!