IEvangelist / azure-cosmos-dotnet-repository

Wraps the .NET SDK for Azure Cosmos DB abstracting away the complexity, exposing a simple CRUD-based repository pattern
https://ievangelist.github.io/azure-cosmos-dotnet-repository
MIT License
299 stars 89 forks source link

Difference in Container Policy for UniqueKey by Item & IItem #448

Open Zaigham-Gulzar opened 3 months ago

Zaigham-Gulzar commented 3 months ago

Describe the bug

  1. I have the following entity:

    public class EntityA: Item
    {
    protected override string GetPartitionKeyValue() => Name;
    
    [JsonProperty("name")]
    public string Name { get; set; }
    }

    When I let the code create the container for this EntityA, it works fine for Upsert Operation.

But I don't need to store the key: "type" in my container, and I also wanted to disable the discriminator in Entity for QuerySpecification, so I did this workaround:

  1. I changed my entity to inherit for IItem instead of Item, like this:

    public class EntityA : IItem
    {
    [UniqueKey("id")]
    public string Id { get; set; }
    
    [JsonIgnore]
    public string Type { get; set; } = string.Empty;
    
    [JsonIgnore]
    public string PartitionKey => Name;
    
    [JsonProperty("name")]
    public string Name { get; set; }
    }
  2. As you can see I have disabled storing of Type and ParitionKey by JsonIgnore annotation/decorator.
  3. But when I let the code create container using this entity, i.e. Inherited from IItem, Upsert operation always fails and gives this error: error: Unique index constraint violation.

Expected behavior

  1. It should be performing the upsert operation like it does when EntityA is inherited from Item class.

Actual behavior

  1. It fails to perform the uspert operation with error message: Unique index constraint violation.

Environment summary SDK Version: 8.1.4 OS Version: Windows

Additional context Current Workaround:

  1. I have to create container with EntityA inherited from class Item.
  2. Then I have to stop the project, change the code to inherit EntityA from IItem interface to make this work.
Zaigham-Gulzar commented 3 months ago

Found easier workaround:

  1. If you have access to Azure Cosmos DB in Portal, then create the containers manually.
  2. This way, you won't have to do double run with inheriting from Item then IItem respectively.
  3. This way it works fine.

Another Workaround (weird but works):

  1. If you do not have access to azure portal for creating container(s). Then do the following; A. Create the same entity twice, once by inheriting Item, then by Inheriting IItem. B. In your options builder you will initialize both of them against the same container. C. In your Program.cs (.Net Core 8 for me). I. Do a simple Get Operation to your Entity inherited by Item class, this will create the container with the proper policy. II. Make this Get operation so that you know it won't return anything. III. Make it in a fire and forget manner in a separate thread, Example: _ = Task.Run(() => _repository.GetAsync(id: "id", partitionKeyValue: "key", cancellationToken: cancellationToken ), cancellationToken); IV. This way, when your project starts up, your container will be created with the right policy. V. Then you can do CRUD operations using the entity inherited from Interface: IItem.