I'm working with CosmosDB in an ASP.NET Core application using EF Core. I have a Post
class with an Slug
property that I use as the partition key. However, I'm encountering an error when trying to save a Post
object to CosmosDB.
Here is the Post
class:
public partial class Post
{
public string Id { get; set; }
[Key]
public string Slug { get; set; }
[Required]
[MaxLength(100)]
public string Title { get; set; }
[Required]
[MaxLength(100)]
public string Subtitle { get; set; }
public string Markdown { get; set; }
[Required]
[MaxLength(50)]
public string Author { get; set; }
[DataMember(Name = "created_at")]
[JsonPropertyName("created_at")]
public DateTime? CreatedAt { get; set; }
[DataMember(Name = "updated_at")]
[JsonPropertyName("updated_at")]
public DateTime? UpdatedAt { get; set; }
}
I generate the Id
using Guid.NewGuid().ToString()
and then save the object to CosmosDB:
public async Task<Post> CreatePostAsync(PostInput postInput)
{
PostInputValidator.CheckPostInputRequiredFields(postInput);
Post post = new()
{
Id = Guid.NewGuid().ToString(),
Slug = Guid.NewGuid().ToString() + "-" + postInput.Title.ToLower().Replace(" ", "-") + "-" + postInput.Author.ToLower(),
Title = postInput.Title,
Subtitle = postInput.Subtitle,
Author = postInput.Author,
Markdown = postInput.Markdown,
CreatedAt = DateTime.UtcNow
};
_context.Posts.Add(post);
await _context.SaveChangesAsync();
return post;
}
However, I get the following error:
PartitionKey extracted from document doesn't match the one specified in the header. Learn more: https://aka.ms/CosmosDB/sql/errors/wrong-pk-value
Here's my DbContext
:
public class BlogContext : DbContext, IBlogContext
{
public BlogContext(DbContextOptions<BlogContext> options)
: base(options)
{
}
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>().ToContainer("Posts");
modelBuilder.Entity<Post>().HasPartitionKey(p => p.Slug);
modelBuilder.Entity<Post>().HasNoDiscriminator();
}
}
Here's my Terraform CosmosDB setup:
resource "azurerm_cosmosdb_account" "gt_cosmosdb" {
name = "gt-cosmosdb"
location = azurerm_resource_group.gt_rg.location
resource_group_name = azurerm_resource_group.gt_rg.name
offer_type = "Standard"
kind = "GlobalDocumentDB"
enable_free_tier = true
consistency_policy {
consistency_level = "Session"
}
geo_location {
location = azurerm_resource_group.gt_rg.location
failover_priority = 0
}
}
resource "azurerm_cosmosdb_sql_database" "gt_database" {
name = "gt-db"
resource_group_name = azurerm_cosmosdb_account.gt_cosmosdb.resource_group_name
account_name = azurerm_cosmosdb_account.gt_cosmosdb.name
}
resource "azurerm_cosmosdb_sql_container" "gt_container" {
name = "Posts"
resource_group_name = azurerm_cosmosdb_account.gt_cosmosdb.resource_group_name
account_name = azurerm_cosmosdb_account.gt_cosmosdb.name
database_name = azurerm_cosmosdb_sql_database.gt_database.name
partition_key_path = "/slug"
throughput = 400
}
Things I've tried:
Id
as a GUID and using .ToString()
Despite this, the error persists. It appears the partition key isn't matching, even though I've configured it to use the Slug
in both EF Core and my Terraform configuration.
Questions:
Any help or guidance would be greatly appreciated!
This is just a shot in the dark, but I believe the partition key is case-sensitive, and currently the casing between your actual partition key property is different from what you've specified in the Terraform.
Try either changing the Terraform to:
partition_key_path = "/Slug"
Or change the JSON name of your Slug
property:
[Key]
[JsonProperty("slug")]
public string Slug { get; set; }
Whichever works best for you.