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

Error when using async queries involving result operators and projecting a collection (N+1 queries scenario) #6534

Closed
serber opened this issue Sep 15, 2016 · 7 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

@serber
Copy link

serber commented Sep 15, 2016

Steps to reproduce

I have method named GetSeriesData:

private IQueryable<SeriesData> GetSeriesData(IQueryable<Series> query, long? userId = null)
{
    DateTime date = DateTime.Today.AddMonths(1);

    IQueryable<SeriesData> seriesDataQuery = query.Select(x => new SeriesData
    {
        Series = x,
        Subscribed = userId.HasValue && x.Subscriptions.Any(y => y.UserId == userId),
        CurrentSeasonNumber = x.Episodes.Where(z => z.ReleaseDate.HasValue && z.ReleaseDate < date).Max(y => y.SeasonNumber),
        Channel = x.Channel,
        Country = x.Channel.Country,
        ReleaseGroups = x.Episodes.SelectMany(z => z.Releases)
                                    .Select(y => y.ReleaseGroup)
                                    .OrderBy(y => y.Name)
                                    .Distinct()
                                    .Select(r => new ReleaseGroupData
                                    {
                                        ReleaseGroup = r,
                                        Subscribed = userId.HasValue && x.Subscriptions.Any(y => y.UserId == userId && y.ReleaseGroupId == r.Id)
                                    }).ToList()
    });

    return seriesDataQuery;
}

I call GetSeriesData method:

public async Task<SeriesData> Get(IFindSeriesParameters parameters, long? userId)
{
    DbSet<Series> seriesRepository = _dataContext.Set<Series>();
    IQueryable<Series> seriesQuery;

    if (parameters.Id.HasValue)
    {
        seriesQuery = seriesRepository.Where(x => x.Id == parameters.Id);
    }
    else if (!string.IsNullOrEmpty(parameters.UniqueUrl))
    {
        seriesQuery = seriesRepository.Where(x => x.UniqueUrl == parameters.UniqueUrl);
    }
    else
    {
        seriesQuery = seriesRepository;
    }

    SeriesData seriesData = await GetSeriesData(seriesQuery, userId).SingleOrDefaultAsync();
    return seriesData;
}

The issue

Calling SingleOrDefaultAsync throws exception

Exception message:
System.ArgumentException: Incorrect number of arguments supplied for call to method 'System.Threading.Tasks.Task`1[System.Boolean] GetResult[Boolean](System.Collections.Generic.IAsyncEnumerable`1[Microsoft.EntityFrameworkCore.Storage.ValueBuffer], System.Threading.CancellationToken)'

Stack trace:
System.ArgumentException: Incorrect number of arguments supplied for call to method 'System.Threading.Tasks.Task`1[System.Boolean] GetResult[Boolean](System.Collections.Generic.IAsyncEnumerable`1[Microsoft.EntityFrameworkCore.Storage.ValueBuffer], System.Threading.CancellationToken)'
   at System.Dynamic.Utils.ExpressionUtils.ValidateArgumentCount(MethodBase method, ExpressionType nodeKind, Int32 count, ParameterInfo[] pis)
   at System.Linq.Expressions.Expression.Call(MethodInfo method, Expression arg0)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ExpressionVisitorBase.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalResultOperatorHandler.HandleResultOperator(EntityQueryModelVisitor entityQueryModelVisitor, ResultOperatorBase resultOperator, QueryModel queryModel)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, Int32 index)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, Int32 index)
   at Remotion.Linq.QueryModelVisitorBase.VisitResultOperators(ObservableCollection`1 resultOperators, 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.VisitBinary(BinaryExpression node)
   at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
   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 Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.ReplaceClauseReferences(Expression expression, IQuerySource querySource, Boolean inProjection)
   at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitSelectClause(SelectClause selectClause, 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.CreateAsyncQueryExecutor[TResult](QueryModel queryModel)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddAsyncQuery[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.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.SingleOrDefaultAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at MySeries.Core.Services.SeriesService.<Get>d__8.MoveNext() in D:\Sources\myseries-2\MySeries.Core\Services\SeriesService.cs:line 174
—- End of stack trace from previous location where exception was thrown —-
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at MySeries.Web.Controllers.SeriesController.<Details>d__5.MoveNext() in D:\Sources\myseries-2\MySeries.Web\Controllers\SeriesController.cs:line 65
—- End of stack trace from previous location where exception was thrown —-
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionMethodAsync>d__27.MoveNext()
—- End of stack trace from previous location where exception was thrown —-
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeNextActionFilterAsync>d__25.MoveNext()
—- End of stack trace from previous location where exception was thrown —-
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeNextResourceFilter>d__22.MoveNext()
—- End of stack trace from previous location where exception was thrown —-
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeAsync>d__20.MoveNext()
—- End of stack trace from previous location where exception was thrown —-
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
—- End of stack trace from previous location where exception was thrown —-
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
—- End of stack trace from previous location where exception was thrown —-
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
—- End of stack trace from previous location where exception was thrown —-
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
—- End of stack trace from previous location where exception was thrown —-
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
—- End of stack trace from previous location where exception was thrown —-
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()

But if i call SingleOrDefault instead of SingleOrDefaultAsync all works fine
Also this code works with EF6

@maumar
Copy link
Contributor

maumar commented Jan 4, 2017

Per information in #7284, this is a regression introduced in 1.1. Should we move this to 1.1.1? @divega

@divega divega modified the milestones: 1.1.1, 2.0.0 Jan 4, 2017
@divega
Copy link
Contributor

divega commented Jan 4, 2017

Thanks @maumar. Moved.

maumar added a commit that referenced this issue Jan 5, 2017
Problem was that during result operator processing, when creating expression for GetResult involving InjectParameter call we were not propagating CancellationToken. Fix is to call a helper method that takes care of that, rather than Expression.Call.
ysmoradi added a commit to bitfoundation/bitplatform that referenced this issue Jan 7, 2017
maumar added a commit that referenced this issue Jan 11, 2017
Problem was that during result operator processing, when creating expression for GetResult involving InjectParameter call we were not propagating CancellationToken. Fix is to call a helper method that takes care of that, rather than Expression.Call.
@maumar
Copy link
Contributor

maumar commented Jan 11, 2017

Fixed in fba433e

@maumar maumar closed this as completed Jan 11, 2017
@divega
Copy link
Contributor

divega commented Jan 12, 2017

@maumar Is the fix for this issue checked in the 1.1.1 branch? Should the issue be reopened for approval?

@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 Jan 12, 2017
@maumar maumar reopened this Jan 12, 2017
@maumar maumar changed the title Problems with LINQ async methods Error when using async queries involving result operators and projecting a collection (N+1 queries) Jan 12, 2017
@maumar maumar changed the title Error when using async queries involving result operators and projecting a collection (N+1 queries) Error when using async queries involving result operators and projecting a collection (N+1 queries scenario) Jan 12, 2017
@Eilon
Copy link
Member

Eilon commented Jan 19, 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.

@RehanSaeed
Copy link

Is there any indication when the 1.1.1 release will go public? Alternatively, is there a workaround for this?

@Eilon
Copy link
Member

Eilon commented Feb 17, 2017

@RehanSaeed it's about 2 - 3 weeks out. We're working on setting up a MyGet feed so people can try out the patch fixes.

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

6 participants