Efcore: Lazy loading proxy comparison throws"could not be translated" InvalidOperationException

Created on 23 Jan 2020  路  4Comments  路  Source: dotnet/efcore

A where clause comparing a lazy loading proxy to a navigation property of a table is throwing an InvalidOperationException like the one below on .NET Core 3.0 and 3.1. This worked on .NET Core 2.1. While it's possible to work around this by replacing a particular instance with a key comparison, tracking down all of the instances in our project would be a lot of work.

The error also suggests that EF is trying to do a join instead of just comparing the proxy's primary key to the child table's foreign key.

The query is:
```C#
var eventTeams = await (from Team team in _context.Teams
where team.Event == myEvent // proxy fetched by a previous query
select team).ToListAsync();


The types involved are a simple parent-child relationship:

```C#
    public class Event
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ID { get; set; }

        // other columns
    }

    public class Team
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ID { get; set; }

        // The event the team is a part of
        public int EventID { get; set; }

        // The event the team is a part of
        [Required]
        public virtual Event Event { get; set; }

        // Other columns
    }

The full exception is:

  'The LINQ expression 'Where<TransparentIdentifier<Team, Event>>(
    source: Join<Team, Event, Nullable<int>, TransparentIdentifier<Team, Event>>(
        outer: Cast<Team>(DbSet<Team>), 
        inner: DbSet<Event>, 
        outerKeySelector: (e) => Property<Nullable<int>>(e, "EventID"), 
        innerKeySelector: (e0) => Property<Nullable<int>>(e0, "ID"), 
        resultSelector: (o, i) => new TransparentIdentifier<Team, Event>(
            Outer = o, 
            Inner = i
        )), 
    predicate: (e) => e.Inner == (Unhandled parameter: __myEvent_0))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'
  at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.<VisitMethodCall>g__CheckTranslated|8_0(ShapedQueryExpression translated, <>c__DisplayClass8_0& )
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   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__DisplayClass12_0`1.<ExecuteAsync>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
   at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.<ToListAsync>d__64`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()

Further technical details

EF Core version: 3.1
Database provider:Microsoft.EntityFrameworkCore.SqlServer
Target framework: 3.1
Operating system: Windows 10
IDE: Visual Studio 2019 16.4.3

area-query closed-fixed customer-reported type-bug

All 4 comments

It turns out this only repros if you put the type of the variable in the LINQ query, so this works:

var eventTeams = from team in _context.Teams
where team.Event == Event
select team;

But this doesn't

var eventTeams = from Team team in _context.Teams
where team.Event == Event
select team;

Calling query extension methods directly also works.

Given Event is an entityType, the where predicate in exception message should have been re-written into entity equality.
cc: @roji

We can add it to my pile of EE issues.

related #20164

Was this page helpful?
0 / 5 - 0 ratings