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

EF 6.0.0 and 6.0.1: sub-lists are no longer loaded #27105

Closed
MarcDrexler opened this issue Jan 4, 2022 · 2 comments
Closed

EF 6.0.0 and 6.0.1: sub-lists are no longer loaded #27105

MarcDrexler opened this issue Jan 4, 2022 · 2 comments
Assignees
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported Servicing-approved type-bug
Milestone

Comments

@MarcDrexler
Copy link

Description

After upgrading from 5.0.13 to 6.0.0 or 6.0.1, I can no longer load sublists and instead get an exception.

image

Exception Details

System.ArgumentException
  HResult=0x80070057
  Message=GenericArguments[2], 'System.Collections.Generic.List`1[<>f__AnonymousType1`2[System.Guid,System.String]]', on 'Void PopulateCollection[TCollection,TElement,TRelatedEntity](Int32, Microsoft.EntityFrameworkCore.Query.QueryContext, System.Data.Common.DbDataReader, Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryResultCoordinator, System.Func`3[Microsoft.EntityFrameworkCore.Query.QueryContext,System.Data.Common.DbDataReader,System.Object[]], System.Func`3[Microsoft.EntityFrameworkCore.Query.QueryContext,System.Data.Common.DbDataReader,System.Object[]], System.Func`3[Microsoft.EntityFrameworkCore.Query.QueryContext,System.Data.Common.DbDataReader,System.Object[]], System.Collections.Generic.IReadOnlyList`1[Microsoft.EntityFrameworkCore.ChangeTracking.ValueComparer], System.Collections.Generic.IReadOnlyList`1[Microsoft.EntityFrameworkCore.ChangeTracking.ValueComparer], System.Collections.Generic.IReadOnlyList`1[Microsoft.EntityFrameworkCore.ChangeTracking.ValueComparer], System.Func`5[Microsoft.EntityFrameworkCore.Query.QueryContext,System.Data.Common.DbDataReader,Microsoft.EntityFrameworkCore.Query.Internal.ResultContext,Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryResultCoordinator,TRelatedEntity])' violates the constraint of type 'TRelatedEntity'.
  Source=System.Private.CoreLib
  StackTrace:
   at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e)
   at System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type[] methodInstantiation)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitNew(NewExpression node)
   at System.Linq.Expressions.NewExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.ProcessShaper(Expression shaperExpression, RelationalCommandCache& relationalCommandCache, LambdaExpression& relatedDataLoaders, Int32& collectionId)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitShapedQuery(ShapedQueryExpression shapedQueryExpression)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at EfCorePopulateCollectionProblem.Program.Main(String[] args) in C:\Users\MarcDrexler\source\repos\EfCore\EfCorePopulateCollectionProblem\Program.cs:line 11

  This exception was originally thrown at this call stack:
    [External Code]

Inner Exception 1:
VerificationException: Method Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor+ShaperProcessingExpressionVisitor.PopulateCollection: type argument 'System.Collections.Generic.List`1[<>f__AnonymousType1`2[System.Guid,System.String]]' violates the constraint of type parameter 'TRelatedEntity'.

Code

A repository to demonstrate the bug can be found here:
https://github.com/MarcDrexler/EfCorePopulateCollectionProblem

To verify the problem, simply press F5 and it will throw the exception.
Connection string and database is not needed.

Provider and version information

EF Core version: tested in 6.0.0 + 6.0.1
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: NET 6.0
Operating system: Windows 11
IDE: Visual Studio 2022 17.1

@ajcvickers
Copy link
Member

@smitpatel Confirmed regression on 6.0. SQL generated in 5.0:

      SELECT [e].[Id], [t].[Id], [t].[Id0], [t].[Prop]
      FROM [EntityOnes] AS [e]
      LEFT JOIN (
          SELECT [e0].[Id], [e1].[Id] AS [Id0], [e1].[Prop], [e0].[EntityOneId]
          FROM [EntityTwo] AS [e0]
          LEFT JOIN [EntityThree] AS [e1] ON [e0].[Id] = [e1].[EntityTwoId]
      ) AS [t] ON [e].[Id] = [t].[EntityOneId]
      ORDER BY [e].[Id], [t].[Id], [t].[Id0]

Code:

public class EntityOne
{
    public Guid Id { get; set; }

    public List<EntityTwo> ListA { get; set; }
}

public class EntityTwo
{
    public Guid Id { get; set; }

    public List<EntityThree> ListB { get; set; }
}

public class EntityThree
{
    public Guid Id { get; set; }

    public string Prop { get; set; }
}

public class SomeDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer(Your.ConnectionString)
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();

    public DbSet<EntityOne> EntityOnes { get; set; }
    public DbSet<EntityTwo> EntityTwos { get; set; }
    public DbSet<EntityTwo> EntityThrees { get; set; }
}

public class Program
{
    public static void Main()
    {
        using (var context = new SomeDbContext())
        {
            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();

            var result = context.Set<EntityOne>()
                .Select(x =>
                    new
                    {
                        x.Id,
                        ListWithSubList = x.ListA.Select(b =>
                            b.ListB.Select(o => new
                            {
                                o.Id, o.Prop
                            }))
                    })
                .ToList();
        }
    }
}

smitpatel added a commit that referenced this issue Jan 6, 2022
We copied type from subquery itself which is always Queryable type because of conversion we do. We need to convert it back to enumerable.
Issue happens only when nested level because we use element type so for 1 level queryable is gone. But for nested level we get Queryable<T> as element type on outer which is not assignable from List<T>
The conversion doesn't cause issue with user having Queryable in the result since that throws exception much earlier.

Resolves #27105
@smitpatel
Copy link
Contributor

We will discuss in triage if we want to patch this. Created PR against 6.0 for now.

@smitpatel smitpatel added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jan 6, 2022
@ajcvickers ajcvickers added this to the 6.0.x milestone Jan 7, 2022
@ajcvickers ajcvickers modified the milestones: 6.0.x, 6.0.2 Jan 10, 2022
smitpatel added a commit that referenced this issue Jan 10, 2022
We copied type from subquery itself which is always Queryable type because of conversion we do. We need to convert it back to enumerable.
Issue happens only when nested level because we use element type so for 1 level queryable is gone. But for nested level we get Queryable<T> as element type on outer which is not assignable from List<T>
The conversion doesn't cause issue with user having Queryable in the result since that throws exception much earlier.

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

No branches or pull requests

3 participants