{"record":{"id":"88f8f9abf2dd94df","repo":"dotnet/efcore","slug":"the-setpropertycalls-argument-to-executeupdate","errorCode":null,"errorMessage":"The 'setPropertyCalls' argument to 'ExecuteUpdate' may only contain a chain of 'SetProperty' expressing the properties to be updated.","messagePattern":"The 'setPropertyCalls' argument to 'ExecuteUpdate' may only contain a chain of 'SetProperty' expressing the properties to be updated\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Design/Query/Internal/PrecompiledQueryCodeGenerator.cs","lineNumber":1250,"sourceCode":"            {\n                if (valueSelector is UnaryExpression\n                    {\n                        NodeType: ExpressionType.Quote,\n                        Operand: LambdaExpression unwrappedValueSelector\n                    })\n                {\n                    settersBuilder.SetProperty(propertySelector, unwrappedValueSelector);\n                }\n                else\n                {\n                    settersBuilder.SetProperty(propertySelector, valueSelector);\n                }\n\n                expression = methodCallExpression.Object;\n                continue;\n            }\n\n            throw new InvalidOperationException(RelationalStrings.InvalidArgumentToExecuteUpdate);\n        }\n\n        // The expression tree is nested inside-out (last SetProperty call is the outermost node),\n        // so setters were added in reverse order. Reverse to restore source code order.\n        var settersArray = settersBuilder.BuildSettersExpression();\n        return Expression.NewArrayInit(settersArray.Type.GetElementType()!, settersArray.Expressions.Reverse());\n    }\n\n    private static ITypeSymbol GetTypeSymbol(Compilation compilation, Type type)\n    {\n        if (type.IsByRef || type.IsPointer || type.IsGenericParameter || type.IsByRefLike)\n        {\n            throw new NotSupportedException($\"Unsupported type: {type}\");\n        }\n\n        if (type.IsArray)\n        {\n            var elementSymbol = GetTypeSymbol(compilation, type.GetElementType()!);","sourceCodeStart":1232,"sourceCodeEnd":1268,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Design/Query/Internal/PrecompiledQueryCodeGenerator.cs#L1232-L1268","documentation":"Thrown by ProcessExecuteUpdate while walking the expression tree of an ExecuteUpdate call's setPropertyCalls argument. It expects a nested chain of SetProperty(...) calls on an UpdateSettersBuilder<T>; if the current node does not match that shape the loop aborts and throws InvalidOperationException with RelationalStrings.InvalidArgumentToExecuteUpdate.","triggerScenarios":"A precompiled query contains an ExecuteUpdate whose setters lambda is not a pure chain of UpdateSettersBuilder<T>.SetProperty(...) calls (e.g. includes arbitrary method calls, property reads, or a different structure).","commonSituations":"Building the SetProperty argument dynamically/programmatically with nodes the parser does not recognise; passing a lambda that wraps SetProperty calls inside other expressions; version mismatch where the setter shape changed.","solutions":["Ensure ExecuteUpdate receives a straightforward chain: .ExecuteUpdate(s => s.SetProperty(...).SetProperty(...)).","Do not wrap SetProperty calls inside other method calls or conditional expressions in the setters lambda.","If building the expression programmatically, replicate the exact UpdateSettersBuilder<T>.SetProperty chain shape."],"exampleFix":"// before\n.ExecuteUpdate(s => SomeWrapper(s.SetProperty(p => p.Name, v)))\n// after\n.ExecuteUpdate(s => s.SetProperty(p => p.Name, v))","handlingStrategy":"validation","validationCode":"// Validate ExecuteUpdate setters are a pure SetProperty chain\nstatic bool IsValidExecuteUpdateChain(LambdaExpression setters)\n{\n    var param = setters.Parameters.Single();\n    var node = setters.Body;\n    while (node != param)\n    {\n        if (node is not MethodCallExpression m\n            || m.Method.Name != nameof(UpdateSettersBuilder<int>.SetProperty)) return false;\n        node = m.Object;\n    }\n    return true;\n}","typeGuard":null,"tryCatchPattern":"try { generator.Generate(/*...*/); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"ExecuteUpdate\"))\n{ throw new InvalidOperationException(\"ExecuteUpdate setters must be a chain of SetProperty calls.\", ex); }","preventionTips":["Write ExecuteUpdate setters as a flat chain: .SetProperty(...).SetProperty(...).","Do not wrap SetProperty in other method calls or conditionals.","When building the expression programmatically, mirror the exact UpdateSettersBuilder<T> shape."],"tags":["precompiled-queries","executeupdate","linq","expression-trees"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}