Skip to content

EF Core 10 migrations do not convert ToJson() columns from nvarchar(max) to native json type when upgrading with UseCompatibilityLevel(170) #37275

@joakimriedel

Description

@joakimriedel

Bug description

When upgrading from EF Core 9 to EF Core 10 with UseCompatibilityLevel(170), the migration generator
does not produce an AlterColumn operation to convert existing OwnsOne/OwnsMany columns configured
with ToJson() from nvarchar(max) to native json type.

Important clarifications:

  • New projects work correctly: EF Core 10 generates json column type for ToJson() columns in new
    migrations
  • Primitive collections upgrade correctly: Existing List<string> etc. columns ARE migrated from
    nvarchar(max) to json
  • ToJson() upgrade fails: Existing ToJson() columns created by EF Core 9 are NOT migrated, causing
    runtime failures

This causes runtime failures because EF Core 10 generates SQL that requires native json columns:

  1. INSERT fails: Implicit conversion from data type json to nvarchar(max) is not allowed
  2. SELECT fails: Incorrect syntax near 'RETURNING' (EF Core generates JSON_VALUE(...RETURNING type) which only works with native json columns)

Expected behavior

When generating a migration after upgrading to EF Core 10 with UseCompatibilityLevel(170), an
AlterColumn should be generated to convert existing ToJson() columns from nvarchar(max) to json,
consistent with how primitive collections are handled.

Actual behavior

The generated migration is empty for ToJson() columns. The column remains nvarchar(max) while EF Core
10 generates SQL requiring native json type.

Workarounds

  1. Lower compatibility level to 160: o.UseCompatibilityLevel(160) - disables RETURNING clause but
    loses native JSON benefits
  2. Manual migration: Add AlterColumn statements for each ToJson() column:
    migrationBuilder.AlterColumn<string>(
        name: "Details",
        table: "Blogs",
        type: "json",
        nullable: true,
        oldClrType: typeof(string),
        oldType: "nvarchar(max)",
        oldNullable: true);
  3. Explicit column type: Add .HasColumnType("json") to all ToJson() configurations, then regenerate
    migration:
    modelBuilder.Entity().OwnsOne(b => b.Details, b => b.ToJson().HasColumnType("json"));

Your code

### Model

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

      protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
          => optionsBuilder.UseSqlServer(connectionString, o => o.UseCompatibilityLevel(170));

      protected override void OnModelCreating(ModelBuilder modelBuilder)
      {
          modelBuilder.Entity<Blog>().OwnsOne(b => b.Details, b => b.ToJson());
      }
  }

  public class Blog
  {
      public int Id { get; set; }
      public string Name { get; set; } = "";
      public BlogDetails? Details { get; set; }
  }

  public class BlogDetails
  {
      public string Author { get; set; } = "";
      public int Viewers { get; set; }
  }

  Repro steps

  1. Create project with EF Core 9.0.11 and generate initial migration:
  dotnet ef migrations add Initial
  1. This correctly creates Details as nvarchar(max):
  Details = table.Column<string>(type: "nvarchar(max)", nullable: true)
  2. Upgrade to EF Core 10.0.0 and add UseCompatibilityLevel(170) to DbContext
  3. Generate upgrade migration:
  dotnet ef migrations add UpgradeToEF10
  4. Observe: Migration is empty - no AlterColumn generated
  5. Apply migrations and run query:
  var blogs = await context.Blogs.Where(b => b.Details!.Viewers > 50).ToListAsync();
  6. Observe: Query fails with Incorrect syntax near 'RETURNING'

Stack traces

### INSERT error (when EF Core tries to insert data)

  Microsoft.Data.SqlClient.SqlException (0x80131904): Implicit conversion from data type json to
  nvarchar(max) is not allowed. Use the CONVERT function to run this query.
     at Microsoft.Data.SqlClient.SqlCommand.<>c.b__195_0(Task`1 result)
     at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParamet
  erObject parameterObject, CancellationToken cancellationToken)
     at
  Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection
  connection, CancellationToken cancellationToken)

  ### SELECT error (when querying with JSON property filter)

  Microsoft.Data.SqlClient.SqlException: Incorrect syntax near 'RETURNING'.

  Generated SQL that fails:
  
  SELECT ... FROM [Blogs] AS [b] WHERE JSON_VALUE([b].[Details], '$.Viewers' RETURNING int) > 50

  The RETURNING clause only works with native json columns, not nvarchar(max).

EF Core version

10.0.0

Database provider

Microsoft.EntityFrameworkCore.SqlServer

Target framework

.NET 10.0

Operating system

macOS Tahoe 26.1

IDE

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions