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

Operating on Enum Flags using Enum.GetValues result in wrong SQL generated (_ord) #35821

Open
melchiork opened this issue Mar 20, 2025 · 1 comment

Comments

@melchiork
Copy link

melchiork commented Mar 20, 2025

Bug description

When using Enum.GetValues together with .HasFlags to produce a collection of enum values in an object from DB int column the SQL is generated, but it contain superfluous _ord column in select, which is not part of VALUES. This results in a runtime exception as selecting the _ord fails.

Example code:

[HttpGet("AllButNone")]
public async Task<IActionResult> GetAllButNone(CancellationToken token)
{
    var query = _context.TestEntities.Select(x => new Dto()
    {
        Id = x.Id,
        Names = Enum.GetValues<SomeEnum>().Where(f => x.SomeEnum.HasFlag(f) && f != SomeEnum.None)
            .Select(f => f.ToString())
    });

    return Ok(await query.ToListAsync(token));
}

Example of generated SQL:

SELECT [t].[Id], [v0].[Value], [v0].[_ord]
FROM [TestEntities] AS [t]
OUTER APPLY (
    SELECT [v].[Value], [v].[_ord]
    FROM (VALUES (CAST(0 AS int)), (1), (2), (4), (8)) AS [v]([Value])
    WHERE [t].[SomeEnum] & [v].[Value] = [v].[Value] AND [v].[Value] <> 0
) AS [v0]
ORDER BY [t].[Id], [v0].[_ord]

Your code

Minimal project to reproduce:
Repli1.zip

[HttpGet("AllButNone")]
public async Task<IActionResult> GetAllButNone(CancellationToken token)
{
    var query = _context.TestEntities.Select(x => new Dto()
    {
        Id = x.Id,
        Names = Enum.GetValues<SomeEnum>().Where(f => x.SomeEnum.HasFlag(f) && f != SomeEnum.None)
            .Select(f => f.ToString())
    });

    return Ok(await query.ToListAsync(token));
}

public class Dto()
{
    public int Id { get; set; }

    public IEnumerable<string> Names { get; set; }
}

public class TestEntity
{
    public int Id { get; set; }

    public SomeEnum SomeEnum { get; set; }
}

[Flags]
public enum SomeEnum
{
    None = 0,
    Some = 1,
    More = 2,
    EvenMore = 4,
    Max = 8
}

Stack traces

Microsoft.Data.SqlClient.SqlException (0x80131904): Invalid column name '_ord'.

   at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__211_0(Task`1 result)

   at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()

   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)

--- End of stack trace from previous location ---

   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)

   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)

--- End of stack trace from previous location ---

   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)

   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)

   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)

   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)

   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()

   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)

   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)

   at Repli1.Controllers.TestController.GetAllButNone(CancellationToken token) in C:\Users\Melchior\source\repos\experiments\Repli1\Controllers\TestController.cs:line 35

   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)

   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)

   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)

   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)

   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)

   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)

   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)

   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)

   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)

   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)

   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)

   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)

   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)

   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

ClientConnectionId:8fd19af8-0863-4942-95df-0b88c2d22759

Error Number:207,State:1,Class:16

Verbose output


EF Core version

9.0.3

Database provider

Microsoft.EntityFrameworkCore.SqlServer

Target framework

.NET 8

Operating system

Windows 11

IDE

Visual Studio 2022 17.10.4

@cincuranet
Copy link
Contributor

Related to #34954.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants