Skip to content

Queries fail after upgrading to EF Core 1.1 #7293

@axelheer

Description

@axelheer

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions