'Not able to model data using Microsoft.EntityFrameworkCore.Cosmos

I am following Microsoft's guide on how to model data in Cosmos Db. I am trying to implement something based on the second JSON snippet in this section of the guide.

It says:

This model has the three most recent comments embedded in the post container, which is an array with a fixed set of attributes. The other comments are grouped in to batches of 100 comments and stored as separate items. The size of the batch was chosen as 100 because our fictitious application allows the user to load 100 comments at a time.

enter image description here

From the implementation point of view, posts and comments are separate classes but the partition key is id for posts and postId for comments. The container "post" is the same.

I am using Microsoft.EntityFrameworkCore.Cosmos in a .NET 5.0 app. We have one container called "Users". In my scenario, the user has many logs. Users data is represented by the AppUser entity and the logs data is represented by the Logs entity. I want to store three recent logs in the user document and the rest of the logs of the user in a separate document, just like it is represented in the above example from Microsoft's guide.

So here are my models:

public class AppUser : IdentityUser
{
    public AppUser()
    {
        Logs = new List<Used>();
    }

    public List<Logs> Logs { get; set; }
}

public class Logs
{
    public DateTime Date { get; set; }

    public string Details { get; set; }
}

public class LogDocument : Entity
{
    public LogDocument() : base("LogDocument")
    {
        Logs = new List<Logs>();
    }

    public string UserId { get; set; }
    public List<Logs> Logs { get; set; }
}

public abstract class Entity
{
    public Entity(string type)
    {
        this.Id = Guid.NewGuid().ToString();
        this.Type = type;
    }

    /// <summary>
    /// Object unique identifier
    /// </summary>
    [Key]
    [JsonProperty("Id")]
    public string Id { get; set; }

    /// <summary>
    /// Object type
    /// </summary>
    public string Type { get; private set; }
}

The entity configuration in the database context is:

builder.Entity<AppUser>().HasKey(_ => _.Id);
builder.Entity<AppUser>().HasPartitionKey(_ => _.Id);
builder.Entity<AppUser>().Property(_ => _.ConcurrencyStamp).IsETagConcurrency();    
builder.Entity<AppUser>().OwnsMany(p => p.Logs);

builder.Entity<LogDocument>().HasKey(e => e.Id);
builder.Entity<LogDocument>().HasPartitionKey(_ => _.UserId)
builder.Entity<LogDocument>().OwnsMany(_ => _.Logs);

builder.Entity<AppUser>().ToContainer("Users");
builder.Entity<LogDocument>().ToContainer("Users");

Whenever I run the application I get the following exception:

InvalidOperationException: The partition key property 'Id' on 'AppUser' is mapped as 'Id', but the partition key property 'UserId' on 'LogDocument' is mapped as 'UserId'. All partition key properties need to be mapped to the same store property.

What am I doing wrong? Why should I specify Id as a partition key for LogDocument? If Id is specified as a partition key in the entity configuration of LogDocument, then the error goes away but it is confusing based on how data is represented in the JSON example from Microsoft's guide. There is no key in the comments item. It is just postId and the array of comments.

How would Microsoft's example or my scenario be modelled and configured in a real-world app that uses Microsoft.EntityFrameworkCore.Cosmos?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source