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 :)
Discussion (0)