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

2.1 regression: "variable referenced from scope '', but it is not defined" exception in GroupBy query translation #11904

Closed
JesperTreetop opened this issue May 4, 2018 · 4 comments
Assignees
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. regression type-bug
Milestone

Comments

@JesperTreetop
Copy link

JesperTreetop commented May 4, 2018

A particular form of GroupBy seems to not work with 2.1 yet worked flawlessly in 2.0.

Exception message: variable 'secondGroup' of type 'System.Linq.IGrouping`2[<>f__AnonymousType0`3[System.String,System.Decimal,System.DateTime],EF21Regression.DbC]' referenced from scope '', but it is not defined
Stack trace:
   at System.Linq.Expressions.Compiler.VariableBinder.Reference(ParameterExpression node, VariableStorageKind storage)
   at System.Linq.Expressions.Compiler.VariableBinder.VisitParameter(ParameterExpression node)
   at System.Linq.Expressions.ParameterExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitMember(MemberExpression node)
   at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitMember(MemberExpression node)
   at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
   at System.Linq.Expressions.Compiler.VariableBinder.VisitLambda[T](Expression`1 node)
   at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
   at System.Linq.Expressions.Compiler.VariableBinder.VisitLambda[T](Expression`1 node)
   at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
   at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
   at System.Linq.Expressions.Expression`1.Compile(Boolean preferInterpretation)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateExecutorLambda[TResults]()
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateQueryExecutor[TResult](QueryModel queryModel)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](Expression query, IQueryModelGenerator queryModelGenerator, IDatabase database, IDiagnosticsLogger`1 logger, Type contextType)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass13_0`1.<Execute>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.AddEnumerable(IEnumerable`1 enumerable)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at EF21Regression.Program.Main(String[] args) in c:\EF21Regression\EF21Regression\Program.cs:line 21

Steps to reproduce

This example .NET Core console app project has a single package reference to Microsoft.EntityFrameworkCore.Sqlite. I encounter the problem with version 2.1.0-preview2-final, but not with 2.0.2.

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;

namespace EF21Regression
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var db = new RegressionDbContext())
            {
                db.Database.EnsureDeleted();
                db.Database.EnsureCreated();

                DateTime tenDaysAgo = DateTime.Today.AddDays(-10);

                List<IR> result = db.Cs
                    .Include(c => c.B)
                    .ThenInclude(b => b.A)
                    .Where(joinedData => joinedData.P == 0
                        && joinedData.B.AKey == joinedData.B.A.AKey
                        && joinedData.B.DT > tenDaysAgo)
                    .GroupBy(firstGroup => new
                    {
                        firstGroup.B.A.Name,
                        R = firstGroup.R,
                        D = firstGroup.B.DT,
                    })
                    .GroupBy(secondGroup => secondGroup.Key.Name)
                    .Select(firstSelect => new
                    {
                        Name = firstSelect.Key,
                        Latest = firstSelect.OrderByDescending(z => z.Key.D).First().Key
                    })
                    .Select(secondSelect => new IR
                    {
                        Name = secondSelect.Name,
                        ID = secondSelect.Latest.R * 100,
                        D = secondSelect.Latest.D,
                    })
                    .ToList();
            }
        }
    }


    public class RegressionDbContext : DbContext
    {
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<DbA>().ToTable("dbA");
            modelBuilder.Entity<DbB>().ToTable("dbB");
            modelBuilder.Entity<DbC>().ToTable("dbC");

            modelBuilder.Entity<DbA>()
                .HasIndex(p => p.Name)
                .HasName("IX_Name")
                .IsUnique();
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite("Data Source=regression.db");
        }

        public DbSet<DbA> As { get; set; }
        public DbSet<DbB> Bs { get; set; }
        public DbSet<DbC> Cs { get; set; }
    }

    public class DbC
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long CKey { get; set; }

        [ForeignKey(nameof(BKey))]
        public DbB B { get; set; }
        public long BKey { get; set; }

        public byte P { get; set; }
        public decimal R { get; set; }
    }

    public class DbB
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long BKey { get; set; }
        public DateTime DT { get; set; }

        [ForeignKey(nameof(AKey))]
        public DbA A { get; set; }
        public int AKey { get; set; }

        public virtual ICollection<DbC> Cs { get; set; }
    }

    public class DbA
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int AKey { get; set; }

        [MaxLength(20)]
        public string Name { get; set; }
    }

    public class IR
    {
        public string Name { get; set; }
        public decimal ID { get; set; }
        public DateTime D { get; set; }
    }

}

Further technical details

EF Core version: 2.1.0-preview2-final
Database Provider: Microsoft.EntityFrameworkCore.Sqlite in the regression code example provided above but seen in Microsoft.EntityFrameworkCore.SqlServer in the real project
Operating system: Windows 10 (Version 1709)
IDE: Visual Studio 2017 15.7 Preview 5

@JesperTreetop JesperTreetop changed the title 2.1 regression: variable referenced from scope '', but it is not defined exception in groupby 2.1 regression: "variable referenced from scope '', but it is not defined" exception in GroupBy query translation May 4, 2018
@smitpatel smitpatel added this to the 2.1.0 milestone May 4, 2018
@smitpatel smitpatel assigned maumar and unassigned smitpatel May 4, 2018
@smitpatel
Copy link
Contributor

Passing over to @maumar since he is working on a fix.

maumar added a commit that referenced this issue May 5, 2018
…ut it is not defined" exception in GroupBy query translation

Problem was that we were not correctly handling scenarios where multiple groupbys are present:

- if combined with Include, we would try to create orderings based on grouping keys for each group by. This is incorrect because all group keys apart from the innermost are out of scope of the inner query model (where we attempted to add them)
- if combined with aggregate we would try to translate into group-aggregate pattern and fail.

Fix is to only add ordering for the first grouping in case of include (includes are ignored for multi-groupby scenarios, so there is no risk of collection misalignment) and don't try to convert queries into group-aggregate pattern if multiple groupbys are present in the query.
maumar added a commit that referenced this issue May 5, 2018
…ut it is not defined" exception in GroupBy query translation

Problem was that we were not correctly handling scenarios where multiple groupbys are present:

- if combined with Include, we would try to create orderings based on grouping keys for each group by. This is incorrect because all group keys apart from the innermost are out of scope of the inner query model (where we attempted to add them)
- if combined with aggregate we would try to translate into group-aggregate pattern and fail.

Fix is to only add ordering for the first grouping in case of include (includes are ignored for multi-groupby scenarios, so there is no risk of collection misalignment) and don't try to convert queries into group-aggregate pattern if multiple groupbys are present in the query.
@maumar
Copy link
Contributor

maumar commented May 5, 2018

fixed in af08612

@maumar maumar closed this as completed May 5, 2018
@maumar maumar added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label May 5, 2018
@JesperTreetop
Copy link
Author

Impressively expedient. Will this make it in in time for the rc?

@ajcvickers
Copy link
Member

@JesperTreetop RC1 has already locked down. This fix will be included in the RTM release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. regression type-bug
Projects
None yet
Development

No branches or pull requests

4 participants