Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 31, 2025

Fixes #37026

Description

The change tracker fails to detect changes in complex collections that are nested inside non-collection complex properties. When an entity contains a non-collection complex property (e.g., NestedJson) which itself contains a complex collection (e.g., Items), modifications to the nested collection are not detected by DetectChanges(), causing SaveChanges() to skip the UPDATE statement.

Customer impact

When customers modify nested complex collections, their changes are silently ignored and not persisted to the database. This breaks the expected behavior where all tracked changes should be detected and saved and leads to data loss.
There is a workaround that allows marking the items as modified manually, but this is error-prone.

How found

Customer reported on 10.0.0-rc2

Regression

No, new feature

Testing

Test added

Risk

Low. Localized change that only affect the new complex collections feature.

Original prompt

This section details on the original issue you should resolve

<issue_title>Issue with change tracker not detecting changes on nested complex collections</issue_title>
<issue_description>### Bug description

While making a workaround for this #37009 and until .NET 10 and EF Core 10 are GA I've found more issues.

Looks like EF can't detect changes in nested complex collections (like Items in this example) (which means SaveChanges won't trigger an UPDATE statement).

Your code

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

await using var context = new BlogContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

var blog = new Blog
{
    Name = "Blog1",
    NestedJson = new NestedJson
    {
        Item = new() { Name = "foo" },
        Items =
            [
                new() { Name = "bar" },
                new() { Name = "baz" },
            ]
    }
};
context.Blogs.Add(blog);
await context.SaveChangesAsync();


blog.NestedJson = blog.NestedJson with
{
    Items = [
                new() { Name = "bar" },
                new() { Name = "baz" },
                new() { Name = "new-bar" },
            ]
};


context.ChangeTracker.DetectChanges();

var modified = context.ChangeTracker.Entries().Any(x=>x.State == EntityState.Modified);
Console.WriteLine($"Is Modified: {modified}"); // Output: Is Modified: False (should be True)

public class BlogContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer("Server=localhost;Database=test;User=SA;Password=Abcd5678;Connect Timeout=60;ConnectRetryCount=0;Encrypt=false")
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>().ComplexProperty(e => e.NestedJson, b =>
        {
            b.ToJson();

            b.ComplexProperty(a => a.Item, b =>
            {
                b.Property(x => x.Name).HasJsonPropertyName("name");
            });

            b.ComplexCollection(a => a.Items, b =>
            {
                b.Property(x => x.Name).HasJsonPropertyName("name");
            });
        });
    }
}

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }

    public NestedJson NestedJson { get; set; }
}

public record NestedJson
{
    public NestedItem Item { get; init; }
    public List<NestedItem> Items { get; init; }
}

public record NestedItem
{
    public string Name { get; init; } = string.Empty;
}

Stack traces


Verbose output


EF Core version

10 RC2

Database provider

No response

Target framework

.NET 10 RC2

Operating system

Windows 11

IDE

Visual Studio 2026</issue_description>

Comments on the Issue (you are @copilot in this section)

@roji /cc @AndriySvyryd @roji @mario-mestrovic 10.0 GA is already completely locked down, and anything less than a critical showstopper won't make it in at this point (and this doesn't look like one).

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix change tracker for nested complex collections Fix change tracker not detecting changes in nested complex collections Oct 31, 2025
Copilot AI requested a review from AndriySvyryd October 31, 2025 18:24
@AndriySvyryd
Copy link
Member

@copilot Rewrite the PR summary using this template:

Fixes #{number}

**Description**
{Issue description}

**Customer impact**
{How does the reported issue affects customer's app? Are there workarounds?}

**How found**
{Was it customer reported or found during verification? How many customers are affected?}

**Regression**
{Is it a regression from a released version? Which one?}

**Testing**
{How the changes were tested}

**Risk**
{Low/Medium/High, argument why}

Copy link
Contributor Author

Copilot AI commented Oct 31, 2025

@copilot Rewrite the PR summary using this template:

...

Updated the PR description using the provided template.

@AndriySvyryd AndriySvyryd marked this pull request as ready for review October 31, 2025 20:02
@AndriySvyryd AndriySvyryd requested a review from a team as a code owner October 31, 2025 20:02
@AndriySvyryd AndriySvyryd changed the title Fix change tracker not detecting changes in nested complex collections [release/10.0] Fix change tracker not detecting changes in nested complex collections Oct 31, 2025
@AndriySvyryd AndriySvyryd merged commit 43bcc1f into release/10.0 Nov 3, 2025
8 checks passed
@AndriySvyryd AndriySvyryd deleted the copilot/fix-nested-complex-collection-changes branch November 3, 2025 20:25
@SamMonoRT SamMonoRT added this to the 10.0.1 milestone Nov 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants