Skip to content

[release/10.0] Fix struct complex property nullability when reading EF Core 8.x/9.x model snapshots#37690

Merged
AndriySvyryd merged 5 commits intorelease/10.0from
copilot/fix-complexproperty-nullable-issue
Feb 13, 2026
Merged

[release/10.0] Fix struct complex property nullability when reading EF Core 8.x/9.x model snapshots#37690
AndriySvyryd merged 5 commits intorelease/10.0from
copilot/fix-complexproperty-nullable-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 13, 2026

Fixes #37683

Description

After upgrading from EF Core 9.0 to 10.0, applications with struct-type complex properties receive false PendingModelChangesWarning errors during migration, even when no model changes were made.

EF Core 9.0 generates model snapshots without explicit .IsRequired() calls for struct complex properties because value types are inherently non-nullable in 9.0 (which didn't support optional complex properties). However, EF Core 10.0 added optional complex property support and when reading 9.0 snapshots without explicit .IsRequired(), incorrectly infers struct complex properties as nullable, causing false pending model change warnings.

Customer impact

The issue affects all customers upgrading from EF Core 8.x or 9.x to 10.0 who use struct complex properties.
When customers upgrade their application from EF Core 9.x to 10.0:

  • MigrateAsync() throws PendingModelChangesWarning exception during application startup
  • dotnet ef migrations add generates spurious migration with AlterColumn operations marking columns as nullable
  • Production deployments fail if PendingModelChangesWarning is configured as an error

Workaround: Customers can suppress the warning by configuring ConfigureWarnings to ignore RelationalEventId.PendingModelChangesWarning, or generate an empty migration that incorrectly marks the column as having changed from nullable to non-nullable.

How found

Customer reported on EF 10.0.3

Regression

Yes, introduced in EF Core 10.0.0 when optional complex property support was added

Testing

Added unit tests

Risk

Low - The fix is narrowly scoped to design-time migration generation from snapshots with version "8.x" or "9.x"

Original prompt

This section details on the original issue you should resolve

<issue_title>ComplexProperty treated as nullable after update from EF Core 9.0 to 10.0</issue_title>
<issue_description>### Bug description

Initial migrations created with EF Core 9.0.13. After updating to 10.0.3 with no other code changes, EF Core incorrectly detects a model change for (struct-type) ComplexProperty columns.

Full demo project at https://github.com/markwijnen/EfCorePendingModelChangesIssue

Demo db context:

class DemoDbContext : DbContext
{
    public DbSet<DemoEntity> Entities { get; set; }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<DemoEntity>().ComplexProperty(e => e.Value);
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);
        optionsBuilder.UseSqlite("Data Source=demo.sqlite");
    }
}
class DemoEntity
{
    public int Id { get; set; }
    public DemoValueObject Value { get; set; }
}
struct DemoValueObject
{
    public int Value { get; set; }
}

Initial migration (with Microsoft.EntityFrameworkCore.Sqlite & Microsoft.EntityFrameworkCore.Design 9.0.13 and dotnet ef migrations add EfCore09):

public partial class EfCore09 : Migration
    {
        /// <inheritdoc />
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Entities",
                columns: table => new
                {
                    Id = table.Column<int>(type: "INTEGER", nullable: false)
                        .Annotation("Sqlite:Autoincrement", true),
                    Value_Value = table.Column<int>(type: "INTEGER", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Entities", x => x.Id);
                });
        }

        /// <inheritdoc />
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Entities");
        }
    }

After updating to Microsoft.EntityFrameworkCore.Sqlite & Microsoft.EntityFrameworkCore.Design 10.0.3, MigrateAsync fails with PendingModelChangesWarning, see stack trace below.

EF Core seems to detect model changes for the "Value_Value" column, even though there aren't any.

Running the migration tool again (dotnet ef migrations add EfCore10) adds the following:

public partial class EfCore10 : Migration
{
    /// <inheritdoc />
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.AlterColumn<int>(
            name: "Value_Value",
            table: "Entities",
            type: "INTEGER",
            nullable: false,
            defaultValue: 0,
            oldClrType: typeof(int),
            oldType: "INTEGER",
            oldNullable: true);
    }

    /// <inheritdoc />
    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.AlterColumn<int>(
            name: "Value_Value",
            table: "Entities",
            type: "INTEGER",
            nullable: true,
            oldClrType: typeof(int),
            oldType: "INTEGER");
    }
}

It looks like EF Core thinks that the "Value_Value" column was nullable in the original schema (oldNullable: true in Up method and nullable: true in Down method) even though it wasn't nullable in the initial migration (nullable: false).

Detected in production with Npgsql.EntityFrameworkCore.PostgreSQL. The demo shows the same error occurring with Microsoft.EntityFrameworkCore.Sqlite.

Possibly related to #36494, but this still occurs on 10.0.3.

Your code

https://github.com/markwijnen/EfCorePendingModelChangesIssue

Stack traces

Unhandled exception. System.InvalidOperationException: An error was generated for warning 'Microsoft.EntityFrameworkCore.Migrations.PendingModelChangesWarning': The model for context 'DemoDbContext' has pending changes. Add a new migration before updating the database. See https://aka.ms/efcore-docs-pending-changes. This exception can be suppressed or logged by passing event ID 'RelationalEventId.PendingModelChangesWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.
    at Microsoft.EntityFrameworkCore.Diagnostics.EventDefinition`1.Log[TLoggerCategory](IDiagnosticsLogger`1 logger, TParam arg)
    at Microsoft.EntityFrameworkCore.Diagnostics.RelationalLoggerExtensions.PendingModelChangesWarning(IDiagnosticsLogger`1 diagnostics, Type contextType)
    at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.ValidateMigrations(Boolean useTransaction, String targetMigration)
    at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(Str...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes dotnet/efcore#37683

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

Copilot AI and others added 3 commits February 13, 2026 02:20
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix ComplexProperty treated as nullable after EF Core update Fix struct complex property nullability when reading pre-10.0 model snapshots Feb 13, 2026
Copilot AI requested a review from AndriySvyryd February 13, 2026 02:37
…hanges

- Only check for versions 8 and 9 (inline version check)
- Remove cast to ComplexProperty and use IMutableComplexProperty directly
- Revert all changes to Migrator.cs (runtime processing not needed)

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Copilot AI changed the title Fix struct complex property nullability when reading pre-10.0 model snapshots Fix struct complex property nullability when reading EF Core 8.x/9.x model snapshots Feb 13, 2026
Copilot AI requested a review from AndriySvyryd February 13, 2026 03:10
@AndriySvyryd
Copy link
Copy Markdown
Member

@copilot Update progress by rewriting 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
Copy Markdown
Contributor Author

Copilot AI commented Feb 13, 2026

@copilot Update progress by rewriting the PR summary using this template:

...

Updated the PR description with the required template format.

@AndriySvyryd AndriySvyryd marked this pull request as ready for review February 13, 2026 04:29
@AndriySvyryd AndriySvyryd requested a review from a team as a code owner February 13, 2026 04:29
Copilot AI review requested due to automatic review settings February 13, 2026 04:29
@AndriySvyryd AndriySvyryd changed the title Fix struct complex property nullability when reading EF Core 8.x/9.x model snapshots [release/10.0] Fix struct complex property nullability when reading EF Core 8.x/9.x model snapshots Feb 13, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a regression introduced in EF Core 10.0 that causes false positive PendingModelChangesWarning errors for applications upgrading from EF Core 8.x or 9.x that use struct-type complex properties. The issue occurs because EF Core 10.0 added support for optional complex properties, and when reading snapshots generated by earlier versions (which don't have explicit .IsRequired() calls), EF Core 10.0 incorrectly infers struct complex properties as nullable.

The fix adds processing in SnapshotModelProcessor to explicitly mark struct complex properties as required when loading model snapshots with version "8.x" or "9.x". This ensures that legacy snapshots are correctly interpreted during migration operations. The fix is activated when customers run dotnet ef migrations add, which regenerates the snapshot file with explicit .IsRequired() calls, resolving both design-time and runtime issues.

Changes:

  • Added ProcessComplexProperties method to recursively process complex properties and nested complex properties in entity types
  • Added UpdateComplexPropertyNullability method to set IsNullable = false for struct complex properties in 8.x/9.x snapshots
  • Added comprehensive unit tests covering standard and nested complex properties for both pre-10.0 and 10.0+ snapshots

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/EFCore.Design/Migrations/Internal/SnapshotModelProcessor.cs Added methods to process complex properties and mark struct complex properties as required for 8.x/9.x model snapshots
test/EFCore.Design.Tests/Migrations/Design/SnapshotModelProcessorTest.cs Added three test methods covering struct complex property nullability processing for different version scenarios and nested complex properties

@AndriySvyryd AndriySvyryd requested a review from artl93 February 13, 2026 04:41
Copy link
Copy Markdown
Member

@artl93 artl93 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. Regression in migrating across versions, customer reported.

@AndriySvyryd AndriySvyryd added this to the 10.0.4 milestone Feb 13, 2026
@AndriySvyryd AndriySvyryd merged commit c214374 into release/10.0 Feb 13, 2026
17 of 20 checks passed
@AndriySvyryd AndriySvyryd deleted the copilot/fix-complexproperty-nullable-issue branch February 13, 2026 20:52
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.

5 participants