dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.55k stars 3.13k forks source link

Enum to string conversion is not respected inside anonymous object in a set operation #33770

Closed victor-borges closed 2 weeks ago

victor-borges commented 2 months ago

Problem

For what I could gather, enum to string conversion is not respected inside of set operations over non-entity types.

Code

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

await using var context = new ApplicationDbContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

context.EntitiesA.Add(new EntityA { ExampleEnum = ExampleEnum.ExampleValueA });
context.EntitiesA.Add(new EntityA { ExampleEnum = ExampleEnum.ExampleValueB });
context.EntitiesA.Add(new EntityA { ExampleEnum = ExampleEnum.ExampleValueC });

context.EntitiesB.Add(new EntityB());
context.EntitiesB.Add(new EntityB());
context.EntitiesB.Add(new EntityB());

await context.SaveChangesAsync();

// Works
var entitiesA = await context.EntitiesA.Select(ea => new { ea.Id, ea.ExampleEnum }).ToListAsync();

// Error
var combinedEntities = await context.EntitiesA.Select(ea => new { ea.Id, ea.ExampleEnum })
    .Concat(context.EntitiesB.Select(eb => new { eb.Id, ExampleEnum = ExampleEnum.ExampleValueB }))
    .ToListAsync();

// Same error
var combinedEntities = await context.EntitiesB.Select(eb => new { eb.Id, ExampleEnum = ExampleEnum.ExampleValueB })
    .Concat(context.EntitiesA.Select(ea => new { ea.Id, ea.ExampleEnum }))
    .ToListAsync();

public class ApplicationDbContext : DbContext
{
    public DbSet<EntityA> EntitiesA { get; set; }
    public DbSet<EntityB> EntitiesB { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
        optionsBuilder.UseSqlServer("...").LogTo(Console.WriteLine);

    protected override void OnModelCreating(ModelBuilder modelBuilder) =>
        modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly);
}

public class EntityA
{
    public long Id { get; set; }
    public ExampleEnum ExampleEnum { get; set; }
}

public class EntityB
{
    public long Id { get; set; }
}

public class EntityAConfiguration : IEntityTypeConfiguration<EntityA>
{
    public void Configure(EntityTypeBuilder<EntityA> builder)
    {
        builder.Property(e => e.ExampleEnum).HasConversion<string>();
    }
}

public enum ExampleEnum
{
    ExampleValueA,
    ExampleValueB,
    ExampleValueC
}

Stack Trace

CoreEventId.QueryIterationFailed[10100] (Microsoft.EntityFrameworkCore.Query) 
      An exception occurred while iterating over the results of a query for context type 'ApplicationDbContext'.
      Microsoft.Data.SqlClient.SqlException (0x80131904): Conversion failed when converting the nvarchar value 'ExampleValueA' to data type int.
         at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
         at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
         at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
         at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
         at Microsoft.Data.SqlClient.SqlDataReader.TryHasMoreRows(Boolean& moreRows)
         at Microsoft.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more)
         at Microsoft.Data.SqlClient.SqlDataReader.ReadAsyncExecute(Task task, Object state)
         at Microsoft.Data.SqlClient.SqlDataReader.InvokeAsyncCall[T](SqlDataReaderBaseAsyncCallContext`1 context)
      --- End of stack trace from previous location ---
         at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()

Environment

EF Core version: 8.0.5 Database provider: Microsoft.EntityFrameworkCore.SqlServer 8.0.5 Target framework: .NET 8.0 Operating system: Fedora 40 KDE IDE: Jetbrains Rider 2024.1.2

ajcvickers commented 2 months ago

Looks like part of #10434.

cincuranet commented 2 weeks ago

Dupe of #10434.