Closed Thorarin closed 5 years ago
@Thorarin, you have created really challenging query for EF, but possibly solveabe. LINQ gives freedom of expressing your needs but often it is complicated to translate to the SQL. Just for academical interest, which SQL were produced by version 2.0?
Simplified repro:
public class Activity
{
public int Id { get; set; }
public DateTime DateTime { get; set; }
public List<Point> Points { get; set; }
}
public class CompetitionSeason
{
public int Id { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
public class Point
{
public int Id { get; set; }
public CompetitionSeason CompetitionSeason { get; set; }
public int? Points { get; set; }
}
// Query
(from a in db.Activities
let cs = db.CompetitionSeasons
.First(s => s.StartDate <= a.DateTime && a.DateTime < s.EndDate)
select new
{
cs.Id,
Points = a.Points.Where(p => p.CompetitionSeason == cs)
}
).ToList();
@maumar to de-dupe.
Problem is in nav reweite. We have optimization when navigation is compared to another, and the navigations were converted to navigation joins, we instead compare their keys. However we don't check that both sides of the comparison are converted to navigation joins - we do the conversion separately.
In the repro code, left side is a simple navigation that can be converted, but the right side is a subquery . In this case we should have left the query as is.
in new pipeline the scenario throws during translation:
Operation is not valid due to the current state of the object.
at Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.SqlExpressions.SubSelectExpression.Verify(SelectExpression selectExpression) in D:\git\EntityFrameworkCore\src\EFCore.Relational\Query\Pipeline\SqlExpressions\SubSelectExpression.cs:line 24
at Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.SqlExpressions.SubSelectExpression..ctor(SelectExpression subquery) in D:\git\EntityFrameworkCore\src\EFCore.Relational\Query\Pipeline\SqlExpressions\SubSelectExpression.cs:line 13
at Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) in D:\git\EntityFrameworkCore\src\EFCore.Relational\Query\Pipeline\RelationalSqlTranslatingExpressionVisitor.cs:line 192
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalSqlTranslatingExpressionVisitor.Translate(Expression expression) in D:\git\EntityFrameworkCore\src\EFCore.Relational\Query\Pipeline\RelationalSqlTranslatingExpressionVisitor.cs:line 45
at Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression) in D:\git\EntityFrameworkCore\src\EFCore.Relational\Query\Pipeline\RelationalProjectionBindingExpressionVisitor.cs:line 118
at Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalProjectionBindingExpressionVisitor.VisitNew(NewExpression newExpression) in D:\git\EntityFrameworkCore\src\EFCore.Relational\Query\Pipeline\RelationalProjectionBindingExpressionVisitor.cs:line 199
at System.Linq.Expressions.NewExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression) in D:\git\EntityFrameworkCore\src\EFCore.Relational\Query\Pipeline\RelationalProjectionBindingExpressionVisitor.cs:line 130
at Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalProjectionBindingExpressionVisitor.Translate(SelectExpression selectExpression, Expression expression) in D:\git\EntityFrameworkCore\src\EFCore.Relational\Query\Pipeline\RelationalProjectionBindingExpressionVisitor.cs:line 43
at Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector) in D:\git\EntityFrameworkCore\src\EFCore.Relational\Query\Pipeline\RelationalQueryableMethodTranslatingExpressionVisitor.cs:line 559
at Microsoft.EntityFrameworkCore.Query.Pipeline.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) in D:\git\EntityFrameworkCore\src\EFCore\Query\Pipeline\QueryableMethodTranslatingExpressionVisitor.cs:line 332
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Pipeline.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query) in D:\git\EntityFrameworkCore\src\EFCore\Query\Pipeline\QueryCompilationContext2.cs:line 62
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async) in D:\git\EntityFrameworkCore\src\EFCore\Storage\Database.cs:line 72
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async) in D:\git\EntityFrameworkCore\src\EFCore\Query\Internal\QueryCompiler.cs:line 108
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0() in D:\git\EntityFrameworkCore\src\EFCore\Query\Internal\QueryCompiler.cs:line 97
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler) in D:\git\EntityFrameworkCore\src\EFCore\Query\Internal\CompiledQueryCache.cs:line 84
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler) in D:\git\EntityFrameworkCore\src\EFCore\Query\Internal\CompiledQueryCache.cs:line 59
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query) in D:\git\EntityFrameworkCore\src\EFCore\Query\Internal\QueryCompiler.cs:line 93
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression) in D:\git\EntityFrameworkCore\src\EFCore\Query\Internal\EntityQueryProvider.cs:line 79
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator() in D:\git\EntityFrameworkCore\src\EFCore\Query\Internal\EntityQueryable`.cs:line 94
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
blocked by #15611
blocking issue has been fixed, however this is still broken. Query we currently generate is:
SELECT (
SELECT TOP(1) [c].[Id]
FROM [CompetitionSeasons] AS [c]
WHERE ([c].[StartDate] <= [a].[DateTime]) AND ([a].[DateTime] < [c].[EndDate])), [a].[Id], [t].[Id], [t].[Activity123Id], [t].[CompetitionSeasonId], [t].[Points]
FROM [Activities] AS [a]
LEFT JOIN (
SELECT [p].[Id], [p].[Activity123Id], [p].[CompetitionSeasonId], [p].[Points]
FROM [Points] AS [p]
LEFT JOIN [CompetitionSeasons] AS [c0] ON [p].[CompetitionSeasonId] = [c0].[Id]
WHERE (([c0].[Id] = (
SELECT TOP(1) [c1].[Id]
FROM [CompetitionSeasons] AS [c1]
WHERE ([c1].[StartDate] <= [a].[DateTime]) AND ([a].[DateTime] < [c1].[EndDate]))) AND ([c0].[Id] IS NOT NULL AND (
SELECT TOP(1) [c1].[Id]
FROM [CompetitionSeasons] AS [c1]
WHERE ([c1].[StartDate] <= [a].[DateTime]) AND ([a].[DateTime] < [c1].[EndDate])) IS NOT NULL)) OR ([c0].[Id] IS NULL AND (
SELECT TOP(1) [c1].[Id]
FROM [CompetitionSeasons] AS [c1]
WHERE ([c1].[StartDate] <= [a].[DateTime]) AND ([a].[DateTime] < [c1].[EndDate])) IS NULL)
) AS [t] ON [a].[Id] = [t].[Activity123Id]
ORDER BY [a].[Id], [t].[Id]
exception:
The multi-part identifier "a.DateTime" could not be bound.
The multi-part identifier "a.DateTime" could not be bound.
The multi-part identifier "a.DateTime" could not be bound.
The multi-part identifier "a.DateTime" could not be bound.
The multi-part identifier "a.DateTime" could not be bound.
The multi-part identifier "a.DateTime" could not be bound.
Filed #17112 to last report
@ajcvickers - I am not sure how to track this as with underlying pipeline change, meaning of whole issue has changed.
@smitpatel Fine to stay on the backlog as a bug in translation of the originally reported query.
I've been working on upgrading an application that was built on .NET Core 2.0 and EF Core 2.0 to version 2.1.1 of both. I've run into a specific query which works fine on EF Core 2.0, but is now failing.
The LINQ query in question:
The issue seems to arise in the second projection being done. An
InvalidOperationException
is thrown:If I remove either the
CompetitionSeasonId =
or thePoints =
part of the projection, the query works fine in both EF Core versions. With both of them, it only works in EF Core 2.0.Changing the
Points =
part of the query to this instead seems to work around the problem:Therefore, it seems to have something to do with accessing
competitionSeason.Id
but then also doing a comparison using thecompetitionSeason
object itself.Steps to reproduce
Further technical details
EF Core version: 2.1.1 Database Provider: any (I think, at least Microsoft.EntityFrameworkCore.SqlServer and Microsoft.EntityFrameworkCore.InMemory) Operating system: Windows 10 (1803) IDE: Visual Studio 2017 15.7.4