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.8k stars 3.2k forks source link

Where Clause Fails When Using Properties Initialized in Constructor #35175

Open salihozkara opened 15 hours ago

salihozkara commented 15 hours ago

In EF Core, attempting to use a property initialized in a constructor as part of a Where clause causes a translation exception. The issue occurs specifically when the property being referenced in the Where clause is set during object initialization in the constructor. Without the Where clause, the query executes without issue, but adding a filter referencing the constructor-initialized property leads to an error.

Expected Behavior: The query should allow filtering on properties initialized within the constructor.

Actual Behavior: EF Core throws a translation error, indicating that it cannot map the Where clause involving a constructor-initialized property to SQL.

Include your code

using Microsoft.EntityFrameworkCore;

var options = new DbContextOptionsBuilder<MyDbContext>()
    .UseSqlServer("Server=localhost;Database=EfCoreTestWhere;User ID=sa;Password=Password1;TrustServerCertificate=True")
    .Options;

await using var context = new MyDbContext(options);

context.Database.EnsureDeleted();
context.Database.EnsureCreated();

context.MyEntities.Add(new MyEntity { Name = "Entity 1" });

context.SaveChanges();

var query1 = context.MyEntities.Select(e => new MyModel { Name = e.Name, Id = e.Id });
var query2 = context.MyEntities.Select(e => new MyModel(e.Id) { Name = e.Name });

var entity1 = await query1.FirstOrDefaultAsync(x => x.Id == 1); // Success
var entity2 = await query2.FirstOrDefaultAsync(x => x.Id == 1); // Error

class MyEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
}

class MyModel
{
    public int Id { get; set; }
    public string Name { get; set; }

    public MyModel(int id)
    {
        Id = id;
    }

    public MyModel()
    {
    }
}

class MyDbContext : DbContext
{
    public DbSet<MyEntity> MyEntities { get; set; }

    public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
    {
    }
}

Include stack traces

Include the full exception message and stack trace for any exception you encounter.

Use triple-tick fences for stack traces. For example:

Unhandled exception. System.InvalidOperationException: The LINQ expression 'DbSet<MyEntity>()
    .Where(m => new MyModel{ Name = m.Name }
    .Id == 1)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.<VisitMethodCall>g__CheckTranslated|15_0(ShapedQueryExpression translated, <>c__DisplayClass15_0&)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, LambdaExpression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable`1 source, Expression`1 predicate, CancellationToken cancellationToken)
   at Program.<Main>$(String[] args) in D:\EmptyProjects\EfCoreTest\EfCoreTest\Program.cs:line 20
   at Program.<Main>$(String[] args) in D:\EmptyProjects\EfCoreTest\EfCoreTest\Program.cs:line 20
   at Program.<Main>(String[] args)

Include provider and version information

EF Core version: Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET 9.0 Operating system: Windows 11 IDE: JetBrains Rider 2024.3

cincuranet commented 2 hours ago

@roji @maumar This is another instance of the same problem we discussed couple months back around primary constructors.