Я работаю с CosmosDB в приложении ASP.NET Core, используя EF Core. У меня есть класс Post
со свойством Slug
, которое я использую в качестве ключа раздела. Однако я столкнулся с ошибкой при попытке сохранить объект Post
в CosmosDB.
Вот класс Post
:
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; }
}
Я генерирую Id
, используя Guid.NewGuid().ToString()
, а затем сохраняю объект в 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;
}
Однако я получаю следующую ошибку:
PartitionKey, извлеченный из документа, не соответствует тому, который указан в заголовке. Узнайте больше: https://aka.ms/CosmosDB/sql/errors/wrong-pk-value
Вот мой 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();
}
}
Вот моя настройка Terraform CosmosDB:
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
}
Вещи, которые я пробовал:
Id
в качестве GUID и использование .ToString()
Несмотря на это, ошибка сохраняется. Похоже, что ключ раздела не совпадает, хотя я настроил его на использование Slug
как в EF Core, так и в моей конфигурации Terraform.
Вопросы:
Любая помощь или руководство будут очень признательны!
Кроме того, отредактируйте свой вопрос, чтобы показать примеры данных из вашей коллекции. Сейчас мы можем только догадываться, как это выглядит (и обязательно используйте правильно отформатированный текст, а не скриншот).
Это всего лишь выстрел в темноте, но я считаю, что ключ раздела чувствителен к регистру, и в настоящее время регистр вашего фактического свойства ключа раздела отличается от того, который вы указали в Terraform.
Попробуйте изменить Terraform на:
partition_key_path = "/Slug"
Или измените JSON-имя вашего свойства Slug
:
[Key]
[JsonProperty("slug")]
public string Slug { get; set; }
Какой вариант подойдет вам лучше всего.
Привет @Visual Винсент, я попробовал добавить свойство Json точно так, как вы описали, но, к сожалению, по-прежнему получаю ошибку:
Можете ли вы вставить образец документа (видя его в веб-интерфейсе портала или эмулятора), чтобы он подтвердил регистр? В документе должно быть указано «slug» в нижнем регистре (потому что в вашем контейнере в качестве пути к ключу раздела указан «/slug»).
Из-за этой ошибки нет образцов документов.
@KevinJames К сожалению, мой опыт работы с CosmosDB ограничен. Пробовали ли вы также перевести свойство Id
в нижний регистр на id
, как предложил Дэвид в своем комментарии к вашему вопросу?
Из-за чувствительности к регистру я изменил свойство пули на строчные буквы, и это сработало. Спасибо за ваше предложение. Непонятно, почему свойство JSON сейчас не работает.
К вашему сведению, вам нужно будет сопоставить
Id
сid
, поскольку в каждом документе Cosmos DB естьid
. и, вероятно, то же самое с вашим ключом раздела (Slug
противslug
). Да, и вы создаете свою пулю, включая ее собственную направляющую. Не совсем понимаю, почему вы это делаете и разбиваете по пулям, когда у вас уже есть идентификатор в качестве идентификатора (разделение по пулу, который каждый раз уникален, не принесет вам никакой пользы)