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

Regression when using ImmutableArray's Contains, while Array's Contains method still works. #35102

Closed
fschwiet opened this issue Nov 14, 2024 · 5 comments · Fixed by #35247
Closed
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 regression type-bug
Milestone

Comments

@fschwiet
Copy link

File a bug

I ran into a regression going from 8.0.1 to 9.0.0 using the Sqlite provider. I have some code which is checking if the string value of a column (column name Value) is one of a number of values (using dbKeys.Contains). dbKeys was an ImmutableArray, I found if I used an Array instead it start to work. But I don't see any reason it shouldn't keep working with an ImmutableArray.

Include your code

The following code using ToImmutableArray stopped working when going from 8.0.1 to 9.0.0:

		var dbKeys = dbTags.Select(t => t.Value).Distinct().ToImmutableArray();

		var existingEntities = await context
			.Tags.Where(t => dbKeys.Contains(t.Value))
			.ToArrayAsync(cancellationToken);

But it works if I use ToArray():

		var dbKeys = dbTags.Select(t => t.Value).Distinct().ToArray();

		var existingEntities = await context
			.Tags.Where(t => dbKeys.Contains(t.Value))
			.ToArrayAsync(cancellationToken);

Include stack traces

Unhandled exception. System.ArgumentException: Expression of type 'System.Collections.Immutable.ImmutableArray`1[System.String]' cannot be used for parameter of type 'System.Collecti
ons.Generic.IEnumerable`1[System.String]' of method 'System.Linq.IQueryable`1[System.String] AsQueryable[String](System.Collections.Generic.IEnumerable`1[System.String])' (Parameter 'arg0')
   at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index)
   at System.Linq.Expressions.Expression.Call(MethodInfo method, Expression arg0)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryableMethodNormalizingExpressionVisitor.TryConvertCollectionContainsToQueryableContains(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryableMethodNormalizingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node)
   at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryableMethodNormalizingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryableMethodNormalizingExpressionVisitor.Normalize(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.NormalizeQueryableMethod(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryTranslationPreprocessor.NormalizeQueryableMethod(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.Process(Expression query)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutorExpression[TResult](Expression query)
   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__DisplayClass11_0`1.<ExecuteCore>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   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.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[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToArrayAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)

Include provider and version information

EF Core version: regressed with version 9.0.0, worked for version 8.0.1
Database provider: Microsoft.EntityFrameworkCore.Sqlite regressed with version 9.0.0, worked for version 8.0.1
Target framework: regression seen with net9.0, worked with net8.0
Operating system: Windows 11 Home
IDE: JetBrains Rider 2024.2.5

@roji
Copy link
Member

roji commented Nov 14, 2024

Confirmed regression from 8.0 to 9.0; not specific to SQLite.

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

ImmutableArray<string> tags = ["foo", "bar"];
// List<string> tags = ["foo", "bar"]; // This works

var existingEntities = await context
    .Tags.Where(t => tags.Contains(t.Value))
    .ToArrayAsync();

public class BlogContext : DbContext
{
    public DbSet<Tag> Tags { 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 Tag
{
    public int Id { get; set; }
    public string Value { get; set; }
}

@cincuranet assigning to you as you worked in this area in 9.0, IIRC.

@EvgenyMuryshkin
Copy link

@roji please see additional examples of similar issues.
Depending on class signature (generic or non-generic) and implemented interfaces (IEnumerable and ICollection), EF behavior is different

See repo with examples
https://github.com/EvgenyMuryshkin/EF8PPerf

Image

Thanks,
Regards,
Evgeny

SapiensAnatis added a commit to SapiensAnatis/Dawnshard that referenced this issue Nov 24, 2024
@caxepok
Copy link

caxepok commented Nov 27, 2024

Confirmed regression from 8.0 to 9.0; - Postgres.

    public IAsyncEnumerable<Scope> FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken)
    {
        return _db.Resources.AsNoTracking().Where(r => names.AsEnumerable().Contains(r.Scope))
            .Select(r => new Scope { Name = r.Scope })
            .AsAsyncEnumerable();
    }

Temporary fixed with AsEnumerable

@roji
Copy link
Member

roji commented Nov 28, 2024

@cincuranet note npgsql/efcore.pg#3385 which is about FrozenSet, but seems to be the same issue otherwise.

@cincuranet cincuranet added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Dec 2, 2024
@cincuranet cincuranet added this to the 9.0.1 milestone Dec 2, 2024
@TonyValenti
Copy link

Glad this resolution is coming. We are dealing with this as well.

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 regression type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants