2

I use CosmosDb with the Entity Framework. I need that when saving data if one of the properties is null, it is stored as undefined. Is there any option to initialize DbContext from CosmosClient, or set CosmosSerializationOptions?

I tried the following option, but it does not work for me:

context.Database.GetCosmosClient().ClientOptions.SerializerOptions = new CosmosSerializationOptions()
{
     IgnoreNullValues = true
};

The option without using EF is working:

CosmosClient cosmosClient = new CosmosClientBuilder(EndpointUri, PrimaryKey)
   .WithSerializerOptions(new CosmosSerializationOptions() { IgnoreNullValues = true })
   .Build();
//The current result
{
    "Id": "fad8b443-6d10-4009-853c-efb6aac18031",
    "Discriminator": "User",
    "FirstName": "Charley",
    "LastName": null
}
//Expected result
{
    "Id": "fad8b443-6d10-4009-853c-efb6aac18031",
    "Discriminator": "User",
    "FirstName": "Charley"
}
Roman Marusyk
  • 23,328
  • 24
  • 73
  • 116
Oleksandr
  • 81
  • 2
  • 12

2 Answers2

3

I'm not using Entity Framework in my code, but in searching for the right way to get Cosmos to ignore null values, I found an alternative solution that may work for you.

I was inspired by the answer to this question to add a JsonProperty attribute with ItemNullValueHandling set to NullValueHandling.Ignore for the classes I'm saving, like so:

[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]
public class Foo
{
    [JsonProperty(PropertyName="id")]
    public string Id {get; set;}

    [JsonProperty(PropertyName = "bar")]
    public string Bar { get; set; }

    [JsonProperty(PropertyName = "baz")]
    public string Baz { get; set; }
}

async void Main()
{
    Foo f = new Foo() { Id = "1", Bar = "bar" };
    string azureSqlCoreApiPrimaryKey = "[REDACTED]";
    string azureSqlCoreApiUrl = "[REDACTED]";
    string cosmosDbName = "[REDACTED]";
    string cosmosContainerName = "test";
    CosmosClient cosmosClient = new CosmosClient(azureSqlCoreApiUrl, azureSqlCoreApiPrimaryKey);
    var cosmosDb = cosmosClient.GetDatabase(cosmosDbName);
    var cosmosContainer = cosmosDb.GetContainer(cosmosContainerName);
    
    await cosmosContainer.CreateItemAsync(f);
}

In my tests, the document would have a null 'baz' attribute if and only if I commented out the JsonObject property.

The accepted answer to that question suggests that you modify the options on a JsonSerializer object instead of touching each class you're trying to save. This is analogous to how you tried to modify the serialization options on your CosmosClient, but were ultimately unable to do so. I ended up moving to modifying the CosmosClient serialization options myself, as you demonstrated. But in a case where you can't modify the serialization options, but you can modify the class you're writing, this is a possible workaround.

MikeRoz
  • 41
  • 4
1

I've tried the sample and I found it really has no option to set IgnoreNullValues when initialize the client, and here's the description:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            => optionsBuilder.UseCosmos(
                "https://xxx.documents.azure.com:443/",
                "primary key",
                databaseName: "Tasks",
                options => {
                    options.SerializerOptions(....);//there's no property choice to set
                });

enter image description here

According to this situation, what you can do is modify the entity, such as removing the null property, and I found a similar question in st, I think you can refer to it. And if your entity always exists null value in some specific property(e.g one property 'userConf' may be a null property, you can create another entity without this property), you can even create another entity to meet your requirement.

Roman Marusyk
  • 23,328
  • 24
  • 73
  • 116
Tiny Wang
  • 10,423
  • 1
  • 11
  • 29
  • I am all ears for a direct solution to set 'IgnoreNullValues = true ', I really can't find it. – Tiny Wang Mar 02 '21 at 09:00
  • Yes, I tried to do this with CosmosDbContextOptionsBuilder in the UseCosmos method. The SerializerOptions property is available from under the DbContext object. – Oleksandr Mar 02 '21 at 09:14
  • @RomanMarusyk Yes, I see, I just wanna show there's no option for SerializerOptions, so I can't set this property when call 'UseCosmos', and I also tried to find the place to set it. If there's exactly nowhere to set, that means what I said is right. Thanks sir! – Tiny Wang Mar 02 '21 at 09:27