After upgrading from EF Core 9 to EF Core 10, ExecuteUpdateAsync throws a System.InvalidOperationException when using SetProperty to assign a constant or captured value to a nullable property (int?).
I'm aware of the [breaking change in EF Core 10](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-10.0/breaking-changes#execute-update-expression) where the column setters parameter moved from Expression<Func<...>> to Func<...>. However, the nullable value-type coercion failure seems like it may be an unintended side effect of that change rather than expected behavior.
Exception
System.InvalidOperationException: No coercion operator is defined between types
'System.Func`2[MyApp.Models.MyEntity,System.Nullable`1[System.Int32]]' and 'System.Int32'.
Reproduce
Entity
public class Order
{
public int Id { get; set; }
public int? UpdatedById { get; set; }
public string Status { get; set; }
}
Failing code (worked in EF Core 9)
const int SystemUserId = 1;
await dbContext.Orders
.Where(x => ids.Contains(x.Id))
.ExecuteUpdateAsync(s =>
{
s.SetProperty(p => p.UpdatedById, _ => SystemUserId); // 💥 throws
s.SetProperty(p => p.Status, _ => "Expired");
});
The same pattern with non-nullable properties or string properties does not fail.
Workaround 1 — use entity parameter instead of discard
s.SetProperty(p => p.UpdatedById, p => (int?)SystemUserId);
Workaround 2 — capture as a pre-typed variable
int? systemUserId = SystemUserId;
await dbContext.Orders
.Where(x => ids.Contains(x.Id))
.ExecuteUpdateAsync(s =>
{
s.SetProperty(p => p.UpdatedById, p => systemUserId);
s.SetProperty(p => p.Status, _ => "Expired");
});
Expected behavior
Assigning a constant int value to an int? property via SetProperty should work regardless of whether the lambda uses a discard (_ =>) or an entity parameter (p =>). The implicit int → int? coercion should be handled transparently, as it was in EF Core 9.
Actual behavior
EF Core 10 throws InvalidOperationException at query compilation time. The error originates in TryTranslateSetterValueSelector, suggesting the new Func-based setter pipeline does not handle the int → Nullable<int> coercion when the lambda uses a discarded parameter.
Notably:
- Switching from
_ => to p => resolves the issue, even though the parameter is unused.
- Pre-casting the value to
int? outside the lambda also resolves it.
- Non-nullable value types and reference types (
string) are unaffected.
This suggests the regression is specific to how the discard-parameter lambda's return type is inferred for nullable value types under the new Func-based API.
Stack trace
at System.Linq.Expressions.Expression.GetUserDefinedCoercionOrThrow(ExpressionType coercionType, Expression expression, Type convertToType)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor
.<>c__DisplayClass108_0.<TryTranslateSetters>g__TryTranslateSetterValueSelector|6(...)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor
.<>c__DisplayClass108_0.<TryTranslateScalarSetterValueSelector|5(...)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor
.TryTranslateSetters(...)
at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal
.SqlServerQueryableMethodTranslatingExpressionVisitor.TryTranslateSetters(...)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor
.TranslateExecuteUpdate(...)
Question
Is the nullable coercion failure with _ => an intended consequence of the Expression<Func<...>> → Func<...> migration, or is this a regression that should be handled by the new setter translation pipeline?
Provider and version information
- EF Core version: 10.0.0
- Database provider: Microsoft.EntityFrameworkCore.SqlServer
- Target framework: .NET 10
- Operating system: Linux (Docker)
- IDE: Visual Studio / Rider
After upgrading from EF Core 9 to EF Core 10,
ExecuteUpdateAsyncthrows aSystem.InvalidOperationExceptionwhen usingSetPropertyto assign a constant or captured value to a nullable property (int?).I'm aware of the [breaking change in EF Core 10](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-10.0/breaking-changes#execute-update-expression) where the column setters parameter moved from
Expression<Func<...>>toFunc<...>. However, the nullable value-type coercion failure seems like it may be an unintended side effect of that change rather than expected behavior.Exception
Reproduce
Entity
Failing code (worked in EF Core 9)
The same pattern with non-nullable properties or
stringproperties does not fail.Workaround 1 — use entity parameter instead of discard
Workaround 2 — capture as a pre-typed variable
Expected behavior
Assigning a constant
intvalue to anint?property viaSetPropertyshould work regardless of whether the lambda uses a discard (_ =>) or an entity parameter (p =>). The implicitint→int?coercion should be handled transparently, as it was in EF Core 9.Actual behavior
EF Core 10 throws
InvalidOperationExceptionat query compilation time. The error originates inTryTranslateSetterValueSelector, suggesting the newFunc-based setter pipeline does not handle theint→Nullable<int>coercion when the lambda uses a discarded parameter.Notably:
_ =>top =>resolves the issue, even though the parameter is unused.int?outside the lambda also resolves it.string) are unaffected.This suggests the regression is specific to how the discard-parameter lambda's return type is inferred for nullable value types under the new
Func-based API.Stack trace
Question
Is the nullable coercion failure with
_ =>an intended consequence of theExpression<Func<...>>→Func<...>migration, or is this a regression that should be handled by the new setter translation pipeline?Provider and version information