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

Queries fail after upgrading to EF Core 1.1 #7293

Closed
axelheer opened this issue Dec 21, 2016 · 6 comments
Closed

Queries fail after upgrading to EF Core 1.1 #7293

axelheer opened this issue Dec 21, 2016 · 6 comments
Assignees
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@axelheer
Copy link
Contributor

After upgrading an application to EF Core 1.1 many queries do not work anymore. With the EF Core 1.0.x releases everything was fine. It may have something to do with using generic parameters, but just have a look on the example below.

I was finally able to reproduce this issue within a more or less simple "one-file" demo project, which works fine using EF Core 1.0.2, but crashes using EF Core 1.1. Using the current nightly build 1.2.0-preview1-22878 crashes too by the way.

Unhandled Exception: System.ArgumentException: An item with the same key has already been added. Key: join User u.User in value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[User]) on Property([u], "UserId") equals Property([u.User], "Id")
   at System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(Object key)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.SnapshotQuerySourceMapping(QueryModel queryModel)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.OptimizeJoinClause(JoinClause joinClause, QueryModel queryModel, Int32 index, Action baseVisitAction, MethodInfo operatorToFlatten, Boolean groupJoin)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitJoinClause(JoinClause joinClause, QueryModel queryModel, Int32 index)
   at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, 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.ExpressionVisitors.RelationalEntityQueryableExpressionVisitor.VisitSubQuery(SubQueryExpression expression)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ExpressionVisitorBase.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
   at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection`1 nodes, Func`2 elementVisitor)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
   at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ExpressionVisitorBase.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
   at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ExpressionVisitorBase.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitMember(MemberExpression node)
   at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ExpressionVisitorBase.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
   at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ExpressionVisitorBase.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.ReplaceClauseReferences(Expression expression, IQuerySource querySource, Boolean inProjection)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitWhereClause(WhereClause whereClause, QueryModel queryModel, Int32 index)
   at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, 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)
   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__DisplayClass15_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 System.Linq.Queryable.SingleOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
   at Program.Item[TView](IQueryable`1 query, Guid key) in C:\Users\Axel\Desktop\efcore\Program.cs:line 161
   at Program.Main(String[] args) in C:\Users\Axel\Desktop\efcore\Program.cs:line 153

Steps to reproduce

Just run the "program" below using different EF Core versions.

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using Microsoft.EntityFrameworkCore;

// --- Contracts ---------------------------------------------------------------

public interface IHasKey
{
    Guid Id { get; set; }
}

// --- Models ------------------------------------------------------------------

public class Project : IHasKey
{
    public Guid Id { get; set; }

    public string Name { get; set; }

    public ISet<ProjectUser> User { get; set; }
}

public class ProjectUser : IHasKey
{
    public Guid Id { get; set; }

    public Guid ProjectId { get; set; }

    public Project Project { get; set; }

    public Guid UserId { get; set; }

    public User User { get; set; }
}

public class User : IHasKey
{
    public Guid Id { get; set; }

    public string Name { get; set; }
}

// --- ViewModels --------------------------------------------------------------

public class ProjectView : IHasKey
{
    public Guid Id { get; set; }

    public string Name { get; set; }

    public IEnumerable<PermissionView> Permissions { get; set; }
}

public class PermissionView : IHasKey
{
    public Guid Id { get; set; }

    public Guid UserId { get; set; }

    public string UserName { get; set; }

}

// --- Context -----------------------------------------------------------------

public class ModelContext : DbContext
{
    public DbSet<Project> Project { get; set; }

    public DbSet<ProjectUser> ProjectUser { get; set; }

    public DbSet<User> User { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        var connectionStringBuilder = new SqlConnectionStringBuilder()
        {
            DataSource = "(localdb)\\MSSQLLocalDB",
            InitialCatalog = "EFCore",
            IntegratedSecurity = true
        };

        optionsBuilder.UseSqlServer(connectionStringBuilder.ConnectionString);
    }
}

// --- Test --------------------------------------------------------------------

public class Program
{
    public static void Main(string[] args)
    {
        // Init
        using (var context = new ModelContext())
        {
            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();

            var projects = new[]
            {
                new Project { Name = "Project 1" },
                new Project { Name = "Project 2" },
                new Project { Name = "Project 3" },
            };

            context.Project.AddRange(projects);

            var users = new[]
            {
                new User { Name = "User 1" },
                new User { Name = "User 2" },
                new User { Name = "User 3" },
            };

            context.User.AddRange(users);

            var permissions = (from project in projects
                               from user in users
                               select new ProjectUser
                               {
                                   ProjectId = project.Id,
                                   Project = project,
                                   UserId = user.Id,
                                   User = user
                               }).ToList();

            context.ProjectUser.AddRange(permissions);

            context.SaveChanges();
        }

        // Query
        using (var context = new ModelContext())
        {
            var query = from p in context.Project
                        select new ProjectView
                        {
                            Id = p.Id,
                            Name = p.Name,
                            Permissions = from u in p.User
                                          select new PermissionView
                                          {
                                              Id = u.Id,
                                              UserId = u.UserId,
                                              UserName = u.User.Name
                                          }
                        };

            var target = context.ProjectUser.First();

            Item(query, target.ProjectId);
        }
    }

    public static TView Item<TView>(IQueryable<TView> query, Guid key)
        where TView : IHasKey
    {
        // Boom!
        return query.SingleOrDefault(item => item.Id == key);
    }
}

Further technical details

EF Core version: 1.1.0
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10 / Windows 7
IDE: Visual Studio Code / Visual Studio 2015

@divega divega added this to the 1.1.1 milestone Jan 6, 2017
@divega divega added the type-bug label Jan 6, 2017
@axelheer
Copy link
Contributor Author

axelheer commented Jan 9, 2017

BTW, generic parameters seem not to be the root cause. I've had another crash with a very similar stack trace, but no time to reproduce it with a small sample like above.

@anpete anpete added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jan 18, 2017
@anpete anpete assigned anpete and unassigned anpete Jan 18, 2017
@divega
Copy link
Contributor

divega commented Jan 22, 2017

Reopening as this still needs to go through patch approval process.

@divega divega reopened this Jan 22, 2017
@divega
Copy link
Contributor

divega commented Jan 25, 2017

@anpete could you please write down justification/risk assessment for this fix?

@axelheer
Copy link
Contributor Author

Any ETA for EF Core 1.1.1?

@anpete
Copy link
Contributor

anpete commented Jan 31, 2017

Risk: Low, a one line change that changes a dictionary update from a potentially throwing Add call to an overwriting set accessor operation.
Justification: This change fixes a regression that causes many previously working LINQ queries to fail.

@Eilon
Copy link
Member

Eilon commented Feb 8, 2017

This patch bug is approved. Please use the normal code review process w/ a PR and make sure the fix is in the correct branch, then close the bug and mark it as done.

@anpete anpete closed this as completed Feb 9, 2017
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. type-bug
Projects
None yet
Development

No branches or pull requests

5 participants