efcore: EF Core 1.1.1 has introduced a new ArgumentException for complex queries with with subqueries, if the same subquery is present multiple times in the query model

I saw today that EF Core 1.1 has been released. I made a new branch and upgraded from 1.0. Now several of our integration tests are failing with the below error. I’m not going to attempt to give you the full code base that raises this error; our codebase is massive. Rather I will just paste the line of code that throws the error along with the stack trace and hope this will be helpful to you. In the meantime I’m abandoning my attempt to upgrade until I hear back that this bug has been repaired.

The line of code that raises the exception:

                            var result = pagedResult
                                .Select(bt => new LibraryManagerSubShelf
                                {
                                    TitleStartingLetter = bt.titleStartingLetter.ToUpper()
                                })
                                .ToList();

where pagedResult is an IQueryable<> that has had a .Skip().Take() applied to it. I verified that if the skip+take is removed, the exception is not thrown.

Stack trace:

System.ArgumentException: An item with the same key has already been added.
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryModelExtensions.QueryModelMappingPopulatingVisitor.VisitSubQuery(SubQueryExpression expression)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ExpressionVisitorBase.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitAndConvert[T](ReadOnlyCollection`1 nodes, String callerName)
   at Remotion.Linq.Parsing.RelinqExpressionVisitor.VisitNew(NewExpression expression)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ExpressionVisitorBase.Visit(Expression node)
   at Remotion.Linq.Clauses.SelectClause.TransformExpressions(Func`2 transformation)
   at Remotion.Linq.QueryModel.TransformExpressions(Func`2 transformation)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryModelExtensions.QueryModelMappingPopulatingVisitor.VisitSubQuery(SubQueryExpression expression)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ExpressionVisitorBase.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryModelExtensions.PopulateQueryModelMapping(QueryModel queryModel, Dictionary`2 mapping)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.LiftSubQuery(IQuerySource querySource, Expression itemsExpression, Expression expression)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitMainFromClause(MainFromClause fromClause, QueryModel queryModel)
   at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
   at Microsoft.EntityFrameworkCore.Query.Internal.SqlServerQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateQueryExecutor[TResult](QueryModel queryModel)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](Expression query, INodeTypeProvider nodeTypeProvider, IDatabase database, ILogger logger, Type contextType)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass19_0`1.<CompileQuery>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at Remotion.Linq.QueryableBase`1.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at MyCode.MyRepository.<>c__DisplayClass1_0.<GetDistinctLibraryManagerShelves>b__0(MyDbContext db) in C:\src\MyCode\MyRepository.cs:line 63

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 23 (18 by maintainers)

Commits related to this issue

Most upvoted comments

Justification to include this in 1.1.2 release:

Impact: Medium. This is a regression introduced by patch 1.1.1 and was reported by a customer. However the scenario affected is quite complex - it requires a subquery nested within another subquery.

Risk: Low. Fix is very local - basically we are adding defensive check when trying to add an item to a dictionary. They only scenarios that could possibly be affected by the fix are currently broken due to this bug.

Fixed in 0594995d21b3706821107b84cf35dfe372210add

While having defensive add to dictionary is safe to do, we should also investigate the reason for it to arise and evaluate if we want to preserve the first value or last value. Also if such cases should be impossible (but happening due to bug somewhere else) then defensive check would make it harder for us to catch the issue.