Skip to content

Regression: ExecuteUpdate fails for constant/literals assigned to for nullable int properties #37974

@knopa

Description

@knopa

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 intint? 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 intNullable<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

Metadata

Metadata

Assignees

Type

No fields configured for Bug.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions