dotnet/efcore · error · InvalidOperationException

'ExecuteUpdate' is being used over type

Error message

'ExecuteUpdate' is being used over type '{structuralType}' which is mapped to JSON; 'ExecuteUpdate' on JSON is not supported.

What it means

Thrown when the SetProperty target resolves to a StructuralTypeShaperExpression whose ComplexType is mapped to JSON. EF Core cannot generate an ExecuteUpdate over a complex type that lives inside a JSON column (the JSON column is opaque to the relational update pipeline at this level).

Solutions

  1. Map the complex type to regular columns (ComplexProperty without ToJson) if you need ExecuteUpdate on its members.
  2. Update the JSON-mapped complex type via load-modify-SaveChanges instead of ExecuteUpdate.
  3. Move the updatable scalar out of the JSON complex type into the owning entity.

Example fix

// before
modelBuilder.Entity<Root>().ComplexProperty(r => r.Address, b => b.ToJson("addr"));
await ctx.Set<Root>().ExecuteUpdateAsync(s => s.SetProperty(r => r.Address.City, "x"));
// after
modelBuilder.Entity<Root>().ComplexProperty(r => r.Address);
await ctx.Set<Root>().ExecuteUpdateAsync(s => s.SetProperty(r => r.Address.City, "x"));
Defensive patterns

Strategy: validation

Validate before calling

// Detect JSON-mapped complex types before ExecuteUpdate.
foreach (var ct in ctx.Model.GetEntityTypes().SelectMany(e => e.GetComplexProperties()))
if (ct.ComplexType.IsMappedToJson())
    logger.LogWarning("Complex type {Name} is JSON-mapped; ExecuteUpdate unsupported.", ct.Name);

Prevention

When it happens

Trigger: A complex property configured with ToJson (complex-JSON) and ExecuteUpdate targeting one of its scalar members. The source fires inside the StructuralTypeShaperExpression/IComplexType case of the setter switch when complexType.IsMappedToJson() is true.

Common situations: Using the newer complex-JSON mapping and attempting bulk updates; mixing complex types with JSON columns.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/cfce8dea8fbd4e83. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs:361

                    translatedSetters.Add(new ColumnValueSetter(column, translatedValue));
                    break;
                }

                // A table-split complex type is being assigned a new value.
                // Generate setters for each of the columns mapped to the comlex type.
                case StructuralTypeShaperExpression
                {
                    StructuralType: IComplexType complexType,
                    ValueBufferExpression: StructuralTypeProjectionExpression
                } shaper:
                {
                    Check.DebugAssert(
                        targetProperty is IComplexProperty complexProperty && complexProperty.ComplexType == complexType,
                        "PropertyBase should be a complex property referring to the correct complex type");

                    if (complexType.IsMappedToJson())
                    {
                        throw new InvalidOperationException(
                            RelationalStrings.ExecuteUpdateOverJsonIsNotSupported(complexType.DisplayName()));
                    }

                    var translatedValue = TranslateSetterValueSelector(source, valueSelector, shaper.Type);
                    ProcessComplexType(shaper, translatedValue);

                    break;
                }

                case JsonScalarExpression { Json: ColumnExpression jsonColumn } jsonScalar:
                {
                    var typeMapping = jsonScalar.TypeMapping;
                    Check.DebugAssert(typeMapping is not null);

                    // We should never see a JsonScalarExpression without a path - that means we're mapping a JSON scalar directly to a relational column.
                    // This is in theory possible (e.g. map a DateTime to a 'json' column with a single string timestamp representation inside, instead of to
                    // SQL Server datetime2), but contrived and unsupported.
                    Check.DebugAssert(jsonScalar.Path.Count > 0);

View on GitHub (pinned to 3a2006ef56)