Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 28 additions & 13 deletions src/EFCore.Design/Query/Internal/PrecompiledQueryCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1170,6 +1170,11 @@ private static NewArrayExpression ProcessExecuteUpdate(MethodCallExpression exec
var settersParameter = settersLambda.Parameters.Single();
var expression = settersLambda.Body;

// Use a Stack to reverse the order of processing.
// The expression tree is nested (Last Call is the Outer-most node).
// We want to process them First -> Last.
var calls = new Stack<MethodCallExpression>();

while (expression != settersParameter)
{
if (expression is MethodCallExpression
Expand All @@ -1187,26 +1192,36 @@ private static NewArrayExpression ProcessExecuteUpdate(MethodCallExpression exec
} methodCallExpression
&& methodCallExpression.Method.DeclaringType.GetGenericTypeDefinition() == typeof(UpdateSettersBuilder<>))
{
if (valueSelector is UnaryExpression
{
NodeType: ExpressionType.Quote,
Operand: LambdaExpression unwrappedValueSelector
})
{
settersBuilder.SetProperty(propertySelector, unwrappedValueSelector);
}
else
{
settersBuilder.SetProperty(propertySelector, valueSelector);
}

// Push to stack to process later
calls.Push(methodCallExpression);
expression = methodCallExpression.Object;
continue;
}

throw new InvalidOperationException(RelationalStrings.InvalidArgumentToExecuteUpdate);
}

// Process the stack (First-In, Last-Out) effectively reversing the tree traversal
// so setters are added in the order they were written in source code.
foreach (var methodCallExpression in calls)
{
var propertySelector = (LambdaExpression)((UnaryExpression)methodCallExpression.Arguments[0]).Operand;
var valueSelector = methodCallExpression.Arguments[1];

if (valueSelector is UnaryExpression
{
NodeType: ExpressionType.Quote,
Operand: LambdaExpression unwrappedValueSelector
})
{
settersBuilder.SetProperty(propertySelector, unwrappedValueSelector);
}
else
{
settersBuilder.SetProperty(propertySelector, valueSelector);
}
}

return settersBuilder.BuildSettersExpression();
}

Expand Down
Loading