dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.76k stars 3.18k forks source link

Cannot set an owned, nullable JSON collection from empty to null #33452

Open Andreas-Dorfer opened 7 months ago

Andreas-Dorfer commented 7 months ago

I have an entity with an owned, nullable JSON collection (see NullVsEmptyList.zip for a running example):

class ParentEntity
{
    public Guid Id { get; set; }
    public string Name { get; set; } = "";
    public List<ChildEntity>? Children { get; set; }
}

class ChildEntity
{
    public string Name { get; set; } = "";
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<ParentEntity>().OwnsMany(p => p.Children, builder => builder.ToJson());
}

Once Children is persisted as [], I cannot set it to null.

//insert entity
using (MyContext context = new())
{
    ParentEntity parent = new()
    {
        Id = id,
        Name = "A",
        Children = [] //set Children to empty list
    };
    context.Parents.Add(parent);
    await context.SaveChangesAsync();
}

//read and update entity
using (MyContext context = new())
{
    var parent = await context.Parents.FindAsync(id);
    parent!.Name = "B";
    parent.Children = null; //set Children to null;
    await context.SaveChangesAsync(); //SQL update statement doesn't update parent.Children
}

Here's the generated SQL update statement:

UPDATE "Parents" SET "Name" = @p0
WHERE "Id" = @p1
RETURNING 1;

It seems to me like the change tracking doesn't recognize the change from [] to null as a relevant change. If I understand #31831 correctly, [] and null should be considered distinct.

EF Core version: 8.0.3 Database provider: Microsoft.EntityFrameworkCore.Sqlite 8.0.3 (and Npgsql.EntityFrameworkCore.PostgreSQL 8.0.2) Target framework: net8.0 IDE: Visual Studio 2022 17.9.5

fiseni commented 7 months ago

I can confirm this behavior too. Just recently, I changed all JSON collection properties to non-nullable, since it was confusing for the teams not to be able to set it to null.

Btw, no matter if you annotate the collection property as nullable or non-nullable, the underlying db column is always defined as nullable. Not sure if that's by design or if it's a bug. Until recently, collections were never mapped to columns, so I guess this is an artifact of that.