Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Property using Enum with ExecuteUpdateAsync throws 'Object reference not set to an instance of an object.' #35656

Closed
johnwc opened this issue Feb 20, 2025 · 2 comments · Fixed by #35657
Assignees
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported preview-2 regression type-bug
Milestone

Comments

@johnwc
Copy link

johnwc commented Feb 20, 2025

Bug description

When running the code below, the error is always thrown. AuthType is a enum type. In ef 8, this worked without an issue. Upgrading to ef 9, now throws an error. If we move the coalesce out to a variable, and use the variable in the method, all works as normal. But this means we now need to pull down a copy of the row to get the value to coalesce with.

Your code

Error

            await _Data.DbContext.ImportJobs
                .Where(q => q.Source.Code == source && q.Id == jobId)
                .ExecuteUpdateAsync(q => q
                .SetProperty(q => q.AuthData, q => authData ?? q.AuthData)
                .SetProperty(q => q.AuthType, q => model.AuthType ?? q.AuthType)
                .SetProperty(q => q.BaseUri, q => model.BaseUri ?? q.BaseUri)
                .SetProperty(q => q.BaseFilter, q => model.BaseFilter ?? q.BaseFilter)
                .SetProperty(q => q.Description, q => model.Description ?? q.Description)
                .SetProperty(q => q.Enabled, q => model.Enabled ?? q.Enabled)
                .SetProperty(q => q.InitialImport, q => model.InitialImport ?? q.InitialImport)
                .SetProperty(q => q.MaxPerRequest, q => model.MaxPerRequest ?? q.MaxPerRequest)
                .SetProperty(q => q.MaxSkip, q => model.MaxSkip ?? q.MaxSkip)
                .SetProperty(q => q.Name, q => model.Name ?? q.Name)
                .SetProperty(q => q.ReplicateApi, q => model.ReplicateApi ?? q.ReplicateApi)
                );


Does not error

var authType = model.AuthType ?? resoJob.AuthType;
            await _Data.DbContext.ImportJobs
                .Where(q => q.Source.Code == source && q.Id == jobId)
                .ExecuteUpdateAsync(q => q
                .SetProperty(q => q.AuthData, q => authData ?? q.AuthData)
                .SetProperty(q => q.AuthType, authType)
                .SetProperty(q => q.BaseUri, q => model.BaseUri ?? q.BaseUri)
                .SetProperty(q => q.BaseFilter, q => model.BaseFilter ?? q.BaseFilter)
                .SetProperty(q => q.Description, q => model.Description ?? q.Description)
                .SetProperty(q => q.Enabled, q => model.Enabled ?? q.Enabled)
                .SetProperty(q => q.InitialImport, q => model.InitialImport ?? q.InitialImport)
                .SetProperty(q => q.MaxPerRequest, q => model.MaxPerRequest ?? q.MaxPerRequest)
                .SetProperty(q => q.MaxSkip, q => model.MaxSkip ?? q.MaxSkip)
                .SetProperty(q => q.Name, q => model.Name ?? q.Name)
                .SetProperty(q => q.ReplicateApi, q => model.ReplicateApi ?? q.ReplicateApi)
                );

Stack traces

at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.ProcessEvaluatableRoot(Expression evaluatableRoot, State& state, Boolean forceEvaluation)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitLambda[T](Expression`1 lambda)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.Visit[T](ReadOnlyCollection`1 expressions, Func`2 elementVisitor, StateType& aggregateStateType, State[]& expressionStates, Boolean poolExpressionStates)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitMethodCall(MethodCallExpression methodCall)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitMethodCall(MethodCallExpression methodCall)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitMethodCall(MethodCallExpression methodCall)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitMethodCall(MethodCallExpression methodCall)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitMethodCall(MethodCallExpression methodCall)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitMethodCall(MethodCallExpression methodCall)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitMethodCall(MethodCallExpression methodCall)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitMethodCall(MethodCallExpression methodCall)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitMethodCall(MethodCallExpression methodCall)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitMethodCall(MethodCallExpression methodCall)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitLambda[T](Expression`1 lambda)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitUnary(UnaryExpression unary)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.Visit[T](ReadOnlyCollection`1 expressions, Func`2 elementVisitor, StateType& aggregateStateType, State[]& expressionStates, Boolean poolExpressionStates)
   at Microsoft.EntityFrameworkCore.Query.Internal.ExpressionTreeFuncletizer.VisitMethodCall(MethodCallExpression methodCall)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteCore[TResult](Expression query, Boolean async, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteUpdateAsync[TSource](IQueryable`1 source, Expression`1 setPropertyCalls, CancellationToken cancellationToken)
   at Admin.API.Controllers.JobsController.<UpdateJob>d__3.MoveNext() in D:\source\repos\Portal\src\webapi\Controllers\JobsController.cs:line 188

Verbose output


EF Core version

9.0.2

Database provider

Microsoft.EntityFrameworkCore.SqlServer

Target framework

.Net 8

Operating system

No response

IDE

No response

@roji
Copy link
Member

roji commented Feb 20, 2025

Confirmed regression in 9, still occurs in latest main as well. This is very related to #35095 which was fixed for 9.0.1, but that fix did not cover cases where the coalesce expressoin in question was itself the top of an evaluatable tree, as is the case here (it's the lambda body).

Minimal repro
await using var context = new BlogContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

AuthType? authType = AuthType.Bar;
await context.ImportJobs
    .ExecuteUpdateAsync(q => q.SetProperty(q => q.AuthType, q => authType ?? q.AuthType));

public class BlogContext : DbContext
{
    public DbSet<ImportJob> ImportJobs { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer("Server=localhost;Database=test;User=SA;Password=Abcd5678;Connect Timeout=60;ConnectRetryCount=0;Encrypt=false")
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();
}

public class ImportJob
{
    public int Id { get; set; }
    public AuthType AuthType { get; set; }
}

public enum AuthType { Foo, Bar }

roji added a commit to roji/efcore that referenced this issue Feb 20, 2025
@roji roji added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Feb 20, 2025
@roji roji closed this as completed in c54f51d Feb 20, 2025
@roji
Copy link
Member

roji commented Feb 20, 2025

Reopening to consider patching for 9.0.

@roji roji reopened this Feb 20, 2025
roji added a commit to roji/efcore that referenced this issue Mar 3, 2025
roji added a commit to roji/efcore that referenced this issue Mar 3, 2025
roji added a commit to roji/efcore that referenced this issue Mar 3, 2025
roji added a commit to roji/efcore that referenced this issue Mar 4, 2025
@AndriySvyryd AndriySvyryd modified the milestones: 9.0.x, 9.0.4 Mar 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported preview-2 regression type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants