{"record":{"id":"322b8775b1f80ce0","repo":"dotnet/efcore","slug":"jsonpartialexecuteupdatenotsupportedbyprovider","errorCode":"JsonPartialExecuteUpdateNotSupportedByProvider","errorMessage":"The provider in use does not support partial updates with ExecuteUpdate within JSON columns.","messagePattern":"The provider in use does not support partial updates with ExecuteUpdate within JSON columns\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs","lineNumber":923,"sourceCode":"    /// <summary>\n    ///     Provider extension point for implementing partial updates within JSON columns.\n    /// </summary>\n    /// <param name=\"target\">\n    ///     An expression representing the target to be updated; can be either <see cref=\"JsonScalarExpression\" />\n    ///     (when a scalar property is being updated within the JSON column), or a <see cref=\"JsonQueryExpression\" />\n    ///     (when an object or collection is being updated).\n    /// </param>\n    /// <param name=\"value\">The JSON value to be set, ready for use as-is in <see cref=\"QuerySqlGenerator\" />.</param>\n    /// <param name=\"existingSetterValue\">\n    ///     If a setter was previously created for this JSON column, it's value is passed here (this happens when e.g.\n    ///     multiple properties are updated in the same JSON column). Implementations can compose the new setter into\n    ///     the existing one (and return <see langword=\"null\" />), or return a new one.\n    /// </param>\n    protected virtual SqlExpression? GenerateJsonPartialUpdateSetter(\n        Expression target,\n        SqlExpression value,\n        ref SqlExpression? existingSetterValue)\n        => throw new InvalidOperationException(RelationalStrings.JsonPartialExecuteUpdateNotSupportedByProvider);\n\n    private static T? ParameterValueExtractor<T>(\n        QueryContext context,\n        string baseParameterName,\n        List<IComplexProperty>? complexPropertyChain,\n        IProperty property)\n    {\n        var baseValue = context.Parameters[baseParameterName];\n\n        if (complexPropertyChain is not null)\n        {\n            foreach (var complexProperty in complexPropertyChain)\n            {\n                if (baseValue is null)\n                {\n                    break;\n                }\n","sourceCodeStart":905,"sourceCodeEnd":941,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs#L905-L941","documentation":"The base RelationalQueryableMethodTranslatingExpressionVisitor.GenerateJsonPartialUpdateSetter (line 919-923) is a provider extension point that, by default, just throws JsonPartialExecuteUpdateNotSupportedByProvider. A provider (e.g. SQL Server, PostgreSQL) overrides it to emit its JSON modification syntax (JSON_MODIFY, jsonb_set). If the provider in use does not override it, any partial JSON ExecuteUpdate (updating a scalar inside a JSON column) fails.","triggerScenarios":"Using a database provider that has not implemented JSON partial updates (e.g. SQLite, or a third-party provider) and calling ExecuteUpdate that targets a scalar property inside a JSON column, triggering GenerateJsonPartialUpdateSetter.","commonSituations":"Switching from SQL Server to SQLite (which lacks the override) while keeping JSON-mapped complex types; using a community provider with partial JSON support; provider version that predates the JSON ExecuteUpdate work.","solutions":["Switch to a provider that implements JSON partial updates (SQL Server, PostgreSQL Npgsql).","Update the entire JSON column as a whole (SetProperty on the full complex value) instead of a partial scalar path, if the provider supports whole-column updates.","Map the data as flattened columns instead of JSON so partial updates become plain column updates.","Perform the partial JSON update via raw SQL using the database's JSON functions."],"exampleFix":"// before (SQLite does not implement partial JSON ExecuteUpdate)\ndb.Contacts.ExecuteUpdate(s => s.SetProperty(\n    c => c.Address.City, \"NYC\")); // Address is a JSON complex type\n\n// after (map as flattened complex columns instead of JSON)\nmodelBuilder.Entity<Contact>().ComplexProperty(c => c.Address);\ndb.Contacts.ExecuteUpdate(s => s.SetProperty(\n    c => c.Address.City, \"NYC\"));","handlingStrategy":"validation","validationCode":"// Detect provider support before relying on partial JSON ExecuteUpdate.\nvar supportsJsonPartial = db.Database.ProviderName switch\n{\n    \"Microsoft.EntityFrameworkCore.SqlServer\" => true,\n    \"Npgsql.EntityFrameworkCore.PostgreSQL\" => true,\n    _ => false\n};\nif (!supportsJsonPartial) throw new InvalidOperationException(\"Provider lacks JSON partial ExecuteUpdate; flatten columns or use raw SQL.\");","typeGuard":null,"tryCatchPattern":"try { await q.ExecuteUpdateAsync(s => s.SetProperty(e => e.Json.X, v)); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"partial updates\"))\n{ /* switch provider, flatten to columns, or update the whole JSON column via raw SQL */ }","preventionTips":["Confirm your provider overrides GenerateJsonPartialUpdateSetter before using partial JSON updates.","Prefer flattened complex columns for portability across providers.","Keep JSON updates whole-column or use raw SQL with provider JSON functions."],"tags":["efcore","executeupdate","json","provider","sqlite"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}