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

Did Contains stop working on empty list in EF Core 8? #32375

Closed
jozseftuska opened this issue Nov 21, 2023 · 7 comments · Fixed by #32414
Closed

Did Contains stop working on empty list in EF Core 8? #32375

jozseftuska opened this issue Nov 21, 2023 · 7 comments · Fixed by #32414
Assignees
Labels
area-primitive-collections area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported regression Servicing-approved type-bug
Milestone

Comments

@jozseftuska
Copy link

jozseftuska commented Nov 21, 2023

Question

Did Contains stop working on empty list in EF Core 8?
My database server is Microsoft SQL Server 2017, compatibility level is set to 140. A query that was working before on .NET6 and EF Core 6 is no longer functioning.
Do we need to check now when calling contains if the list is empty?

Code

Edit - Full code: repository
The debug view of the query will look like this:

    ...
    .Where(x => List<int> {  }.Contains(x.Key))

Stack traces

The LINQ expression '[Microsoft.EntityFrameworkCore.Query.InlineQueryRootExpression]' could not be translated. Additional information: Empty collections are not supported as inline query roots. 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.Translate(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.TranslateSubquery(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateInternal(Expression expression, Boolean applyDefaultTypeMapping)
   at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.Translate(Expression expression, Boolean applyDefaultTypeMapping)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateExpression(Expression expression, Boolean applyDefaultTypeMapping)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateLambdaExpression(ShapedQueryExpression shapedQueryExpression, LambdaExpression lambdaExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateWhere(ShapedQueryExpression source, LambdaExpression predicate)
   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.Translate(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)
   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.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
   at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.<ToListAsync>d__67`1.MoveNext()

Provider and version information

EF Core version: 8.0.0
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 8.0
Operating system: Windows 11
IDE: Visual Studio 2022 17.8

@jozseftuska jozseftuska changed the title Did Contains stopped working on empty list in EF Core 8? Did Contains stop working on empty list in EF Core 8? Nov 21, 2023
@roji
Copy link
Member

roji commented Nov 21, 2023

@jozseftuska I can't repro this - see the below LINQ query. I need to see an actual code sample here - posting a debug view of a query and a stack trace are not sufficient. Please post a minimal, runnable code sample, or tweak the below sample to make it fail.

Attempted repo
await using var ctx = new BlogContext();
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.EnsureCreatedAsync();

_ = ctx.Blogs.Where(x => new List<int> { }.Contains(x.Id)).ToList();

public class BlogContext : DbContext
{
    public DbSet<Blog> Blogs { 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 Blog
{
    public int Id { get; set; }
    public string? Name { get; set; }
}

@JinHuihui1234
Copy link

JinHuihui1234 commented Nov 22, 2023

I ran into a similar error.
Here is all my code. It works in EF7 but fails in EF8

internal class Program
{
    static void Main(string[] args)
    {
        List<Guid> ids = new List<Guid>();

        Expression<Func<Project, bool>> expression1 = e => ids.Contains(e.Id);
        Expression<Func<Project, bool>> expression2 = CreatePredicate(ids);

        using (MyContext context = new MyContext())
        {
            var result1 = context.Projects.Where(expression1).ToList(); // Right
            var result2 = context.Projects.Where(expression2).ToList(); // Error
        }
    }

    private static Expression<Func<Project, bool>> CreatePredicate(IEnumerable<Guid> ids)
    {
        ParameterExpression parameter = Expression.Parameter(typeof(Project));
        MemberExpression member = Expression.Property(parameter, "Id");
        Expression constant = Expression.Constant(ids.ToList());
        MethodCallExpression methodCall = Expression.Call(constant, typeof(List<Guid>).GetMethod(nameof(List<Guid>.Contains)), member);
        return Expression.Lambda<Func<Project, bool>>(methodCall, parameter);
    }
}

class MyContext : DbContext
{
    public DbSet<Project> Projects { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Data Source=XXXX;Initial Catalog=Test;User Id=sa;Password=XXXX;MultipleActiveResultSets=True;TrustServerCertificate=True;");
        optionsBuilder.LogTo(Console.WriteLine);
        optionsBuilder.EnableSensitiveDataLogging();
        optionsBuilder.EnableDetailedErrors();
    }
}

public class Project
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

The exception is:
System.InvalidOperationException:“The LINQ expression '[Microsoft.EntityFrameworkCore.Query.InlineQueryRootExpression]' could not be translated. Additional information: Empty collections are not supported as inline query roots. 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.”

@jozseftuska
Copy link
Author

Dear @roji, thank you for the quick response. Our query is created using AutoMapper based on the documentation.

I created a minimal example of the issue: repository
This same query was working fine in .NET 6 and EF Core 6.

Looking forward to your answer.

@roji
Copy link
Member

roji commented Nov 24, 2023

Thanks for the repros! I'm currently away but I'll take a look at this next week for sure.

@roji
Copy link
Member

roji commented Nov 26, 2023

Minimal repro is any composing on top of an empty inline array:

_ = ctx.Blogs.Where(b => new int[] { }.Contains(b.Id)).ToList();

The above query in itself is of course contrived, but people may indeed be creating constant nodes programmatically via the Expression API, and this should translate.

Note that this repro doesn't work for List because of #32413.

roji added a commit to roji/efcore that referenced this issue Nov 26, 2023
@roji roji added closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. Servicing-consider labels Nov 26, 2023
roji added a commit to roji/efcore that referenced this issue Nov 27, 2023
roji added a commit that referenced this issue Nov 27, 2023
@roji
Copy link
Member

roji commented Nov 27, 2023

Reopening to consider servicing.

@roji roji reopened this Nov 27, 2023
roji added a commit to roji/efcore that referenced this issue Nov 29, 2023
@ajcvickers ajcvickers added this to the 8.0.2 milestone Nov 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-primitive-collections area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported regression Servicing-approved type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants