Skip to content

EF Core 3.1 Urgent Issue:- ToQuery Method with Left Outer Join Causes an Error although it was working Properly with Previous Version #19708

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
ahmedtolba1984 opened this issue Jan 25, 2020 · 18 comments · Fixed by #19885

Comments

@ahmedtolba1984
Copy link

ahmedtolba1984 commented Jan 25, 2020

In EF Core 2.1, I was able to test SQL View with InMemory Provider using a custom ToQuery() method, like below:-

        public DbSet<CustomerView> CustomerViews { get; set; }
        if (Database.IsInMemory())
            {
                //In memory test query type mappings
                modelBuilder.Entity<CustomerView>().HasNoKey().ToQuery(Build_Customers_Sql_View_InMemory());
            }
        private Expression<Func<IQueryable<CustomerView>>> Build_Customers_Sql_View_InMemory()
        {
            Expression<Func<IQueryable<CustomerView>>> query = () =>
                from customer in Customers
                join customerMembership in CustomerMemberships on customer.Id equals customerMembership.CustomerId into
                    nullableCustomerMemberships
                from customerMembership in nullableCustomerMemberships.DefaultIfEmpty()
                select new CustomerView
                {
                    Id = customer.Id,
                    Name = customer.Name,
                    CustomerMembershipId = customerMembership != null? customerMembership.Id : default(int?),
                    CustomerMembershipName = customerMembership != null ? customerMembership.Name: ""
                };
            return query;
        }

but after i upgrade to EF Core 3.1, I got an exception "System.InvalidOperationException : Processing of the LINQ expression" although my ToQuery method code works properly outside the method.
Kindly, check the stack trace and working sample that produce the issue

System.InvalidOperationException : Processing of the LINQ expression 'DbSet<Customer>
    .GroupJoin(
        outer: DbSet<CustomerMembership>, 
        inner: customer => customer.Id, 
        outerKeySelector: customerMembership => customerMembership.CustomerId, 
        innerKeySelector: (customer, nullableCustomerMemberships) => new { 
            customer = customer, 
            nullableCustomerMemberships = nullableCustomerMemberships
         })' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core. See https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed information.
   at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitConstant(ConstantExpression constantExpression)
   at System.Linq.Expressions.ConstantExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.Expand(Expression query)
   at Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.Process(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__DisplayClass9_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Collections.Generic.IEnumerable<TEntity>.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at EFInMemoryProviderSQLViewIssue.CustomerTests.Create_New_Customer()
Got Exceptions? Include both the message and the stack trace

-->



### Further technical details

EF Core version: 3.1.1
Database provider: (Microsoft.EntityFrameworkCore.InMemory)
Target framework: (.NET Core 3.1)

[EFInMemoryProviderSQLViewIssue.zip](https://github.com/dotnet/efcore/files/4112526/EFInMemoryProviderSQLViewIssue.zip)
IDE: (Visual Studio 2019 16.4.2)

@ahmedtolba1984 ahmedtolba1984 changed the title EF Core 3.1 Urgent Issue:- ToQuery Method with Left Outer Join Causes an Error although it was working with Previous Version EF Core 3.1 Urgent Issue:- ToQuery Method with Left Outer Join Causes an Error although it was working Properly with Previous Version Jan 25, 2020
@ahmedtolba1984
Copy link
Author

@ajcvickers @smitpatel @AndriySvyryd @roji @bricelam

@ahmedtolba1984
Copy link
Author

@ahmedtolba1984
Copy link
Author

Dears, any help ?

@ErikEJ
Copy link
Contributor

ErikEJ commented Jan 27, 2020

@ahmedtolba1984 If you need urgent help, there are paid support options

@ajcvickers
Copy link
Contributor

@ahmedtolba1984 I can reproduce what you are seeing, but I'm not sure why it is failing.

@maumar @roji Could you guys take a look? We might need @smitpatel to take a look when he is back.

@maumar
Copy link
Contributor

maumar commented Jan 27, 2020

GroupJoin method translation is not supported. Problem is that for regular query we run pre-processing step that flattens SelectMany-GroupJoin-DefaultIfEmpty into LeftJoin, which we can translate. When using view however, at the time of flattening the query doesn't have it's Defining query extracted, so the SM-GJ-DIE pattern is not available for flattening. We only peek into defining query during nav rewrite

@maumar
Copy link
Contributor

maumar commented Jan 27, 2020

Fix is to run missing pre-processing steps after the defining query has been extracted, but before the extracted query is put thru nav rewrite itself.

@maumar
Copy link
Contributor

maumar commented Jan 27, 2020

related to #17270

@ahmedtolba1984
Copy link
Author

@maumar Thanks for feedback but when this problem will be solved or Is there any workaround for such issue?

@maumar
Copy link
Contributor

maumar commented Jan 28, 2020

@ahmedtolba1984 no good workaround, at least if you want to use ToQuery. If the issue is very urgent for you, the best approach is probably to apply the fix yourself:
1.) fork the current master
2.) in the code for NavigationExpandingExpressionVisitor, in line 120 (method is VisitConstant, just before processedDefiningQueryBody = Visit(processedDefiningQueryBody);

add the following line of code:

processedDefiningQueryBody = new GroupJoinFlatteningExpressionVisitor().Visit(processedDefiningQueryBody);

@ahmedtolba1984
Copy link
Author

@maumar
Thanks, but i have a question, Does SQLlite support SQL View?
I think if so, i can change my InMemory Provider with SQL Lite

@maumar
Copy link
Contributor

maumar commented Jan 28, 2020

@ahmedtolba1984 unfortunately this issue affects all providers

@maumar
Copy link
Contributor

maumar commented Jan 28, 2020

@ahmedtolba1984 actually, workaround for your specific case could be to write a query already it its LeftJoin form:

            Expression<Func<IQueryable<CustomerView>>> query = () =>
                QueryableExtensions.LeftJoin(Customers, CustomerMemberships, c => c.Id, cm => cm.CustomerId, (customer, customerMembership) => new CustomerView
                {
                    Id = customer.Id,
                    Name = customer.Name,
                    CustomerMembershipId = customerMembership != null ? customerMembership.Id : default(int?),
                    CustomerMembershipName = customerMembership != null ? customerMembership.Name : ""
                });

@smitpatel
Copy link
Contributor

ToQuery method may be removed in #17270.

smitpatel added a commit that referenced this issue Feb 12, 2020
Introduces QueryableMethodNormalizingExpressionVisitor which
- Extract query metadata methods
- Convert from enumerable to queryable
- Convert List.Contains to queryable Contains
- Flatten GroupJoin-SelectMany

Nav expansion now calls this method on query filter/ defining query

Resolves #19708
smitpatel added a commit that referenced this issue Feb 12, 2020
Introduces QueryableMethodNormalizingExpressionVisitor which
- Extract query metadata methods
- Convert from enumerable to queryable
- Convert List.Contains to queryable Contains
- Flatten GroupJoin-SelectMany

Nav expansion now calls this method on query filter/ defining query

Resolves #19708

Part of #18923
smitpatel added a commit that referenced this issue Feb 12, 2020
Introduces QueryableMethodNormalizingExpressionVisitor which
- Extract query metadata methods
- Convert from enumerable to queryable
- Convert List.Contains to queryable Contains
- Flatten GroupJoin-SelectMany

Nav expansion now calls this method on query filter/ defining query

Resolves #19708

Part of #18923
@ajcvickers ajcvickers modified the milestones: 5.0.0, 5.0.0-preview1 Mar 13, 2020
@ajcvickers ajcvickers modified the milestones: 5.0.0-preview1, 5.0.0 Nov 7, 2020
@prashantaggarwal1990
Copy link

prashantaggarwal1990 commented Apr 29, 2021

I am facing an issue after converting the project from .Net core 2.1 to 3.1. I have following linq code:

var query = _context.FileDescriptor.Where(x => x.ClientId == clientId);
var finalQuery = from entity in testquery
join nextVersion in testquery on entity.Id equals nextVersion.PreviousRevisionId into nextVersions
where !nextVersions.Any() && !entity.IsDeleted && entity.FolderId == folderId
select entity
return await finalQuery.FirstOrDefaultAsync(d => !d.IsDeleted && d.FolderId == folderId && d.FileName == fileName, token);

Getting the below error while executing:
System.InvalidOperationException: Processing of the LINQ expression 'DbSet
.Where(x => x.ClientId == __clientId_0)
.GroupJoin(
outer: DbSet
.Where(x => x.ClientId == __clientId_0),
inner: entity => (Nullable)entity.Id,
outerKeySelector: nextVersion => nextVersion.PreviousRevisionId,
innerKeySelector: (entity, nextVersions) => new {
entity = entity,
nextVersions = nextVersions
})' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core. See https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed information.
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.Expand(Expression query)
at Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.Process(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__DisplayClass12_01.<ExecuteAsync>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func1 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, IQueryable1 source, Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable1 source, LambdaExpression expression, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable1 source, Expression`1 predicate, CancellationToken cancellationToken)
Please help..

@smitpatel
Copy link
Contributor

@prashantaggarwal1990 - As the milestone indicates this issue is fixed in 5.0 release and it is not supposed to work in 3.1.

@prashantaggarwal1990
Copy link

prashantaggarwal1990 commented Apr 29, 2021 via email

@smitpatel
Copy link
Contributor

There are few work-around mentioned in the comments above. Apart from that either upgrade to 5.0 or avoid using ToQuery.

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

Successfully merging a pull request may close this issue.

6 participants