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

Invalid query produced when projecting DTO containing subquery that returns a single element #7714

Closed
dougbu opened this issue Feb 24, 2017 · 36 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

@dougbu
Copy link
Member

dougbu commented Feb 24, 2017

Describe what is not working as expected.

Using a simplified version of the #6534 code, get an InvalidOperationException instead of expected compilation failure (pre-1.1.1) or result (with 1.1.1). Main simplification is this one does not involve an optional (1 => 0,1) relationship.

Using the out-of-the-box application database created in a .NET Core web application with Individual User Accounts, add the following to HomeController:

        public async Task<List<Results>> Bug1()
        {
            var val = from c in _dbContext.Users
                      where c.EmailConfirmed
                      orderby c.Email
                      select new Results
                      {
                          Count = c.Claims.Count(x => x.Id <= 3),
                          Name = c.UserName,
                      };

            return await val.ToListAsync();
        }

        public class Results
        {
            public int Count { get; set; }

            public string Name { get; set; }
        }

Then, restore, build and run the application. Navigate to /home/bug and see the stack on the console.

If you are seeing an exception, include the full exceptions details (message and stack trace).

fail: Microsoft.EntityFrameworkCore.Query.Internal.SqlServerQueryCompilationContextFactory[1]
      An exception occurred in the database while iterating the results of a query.
      System.InvalidOperationException: No value provided for required parameter '_outer_Id'.
         at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.CreateCommand(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
         at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.<ExecuteAsync>d__26.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.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable.AsyncEnumerator.<BufferlessMoveNext>d__9.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.EntityFrameworkCore.Storage.Internal.SqlServerExecutionStrategy.<ExecuteAsync>d__6`2.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.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable.AsyncEnumerator.<MoveNext>d__8.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.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.SelectAsyncEnumerable`2.SelectAsyncEnumerator.<MoveNext>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.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.SelectAsyncEnumerable`2.SelectAsyncEnumerator.<MoveNext>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.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.<MoveNext>d__5.MoveNext()
System.InvalidOperationException: No value provided for required parameter '_outer_Id'.
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.CreateCommand(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.<ExecuteAsync>d__26.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.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable.AsyncEnumerator.<BufferlessMoveNext>d__9.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.EntityFrameworkCore.Storage.Internal.SqlServerExecutionStrategy.<ExecuteAsync>d__6`2.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.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable.AsyncEnumerator.<MoveNext>d__8.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.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.SelectAsyncEnumerable`2.SelectAsyncEnumerator.<MoveNext>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.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.SelectAsyncEnumerable`2.SelectAsyncEnumerator.<MoveNext>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.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.<MoveNext>d__5.MoveNext()
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[0]
      An unhandled exception has occurred: No value provided for required parameter '_outer_Id'.
System.InvalidOperationException: No value provided for required parameter '_outer_Id'.
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.CreateCommand(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.<ExecuteAsync>d__26.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.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable.AsyncEnumerator.<BufferlessMoveNext>d__9.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.EntityFrameworkCore.Storage.Internal.SqlServerExecutionStrategy.<ExecuteAsync>d__6`2.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.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable.AsyncEnumerator.<MoveNext>d__8.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.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.SelectAsyncEnumerable`2.SelectAsyncEnumerator.<MoveNext>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.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.SelectAsyncEnumerable`2.SelectAsyncEnumerator.<MoveNext>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.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.<MoveNext>d__5.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.EntityFrameworkCore.EntityFrameworkQueryableExtensions.<ToListAsync>d__129`1.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 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at EntityFramework_6534.Controllers.HomeController.<Bug1>d__6.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.ObjectMethodExecutor.<CastToObject>d__40`1.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 System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(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.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.ExceptionHandlerMiddleware.<Invoke>d__6.MoveNext()

Steps to reproduce

See description above.

Further technical details

EF Core version:

<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.0" PrivateAssets="All" />

Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10
IDE: Visual Studio 2017 RC

@dougbu
Copy link
Member Author

dougbu commented Feb 24, 2017

/cc @maumar

@parys
Copy link

parys commented Mar 7, 2017

Tried to use vs 2017. Migrated projects, all compiled, but when try to get data from database I've got System.InvalidOperationException: 'No value provided for required parameter '_outer_Id'.'

Select Example:

var user = await _context.Users.Where(x => x.Id == id).Select(x => new User
            {
                Id = x.Id,
                Field1Count = x.Fields.Count(y => y.Type == FieldType.Type1)
...}.FirstOrDefaultAsync();

For queries without getting data from navigation properties all is good. All EFcore versions is latest stable 1.1.1(0)(Like mentioned above). VS 2017 Release. In VS 2015 have no problem.
If move this Count query to other query then both of them executed without problems.

Update: I've just realize that's a huge step back, if for 1 entity I can made some additional queries, but I have similar queries that return list, I now I should made additional request for every entity, that a huge overhead.

@szykov
Copy link

szykov commented Mar 9, 2017

The same thing for me:

.Select(r => new SimpleClass
{
  Id = r.Id,
  Name = r.Name,
  Count= r.Entries.Count <-----
}).ToList();

Error: No value provided for required parameter '_outer_Id'.

If I change the code to create an anonymous class like that:

.Select(r => new
{
  Id = r.Id,
  Name = r.Name,
  Count= r.Entries.Count
}).ToList();

Works as usual.

The Error appeared after upgrading to VS 2017.

UPDATE:
If someone wants a workaround before it gets fixed. Here's one with using automapper:

var rows = this.context.data
	.Select(r => new
	{
		Id = r.Id,
		Name = r.Name,
		Description = r.Description,
		Count = r.Entries.Count
	}).ToList();

var config = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);
var mapper = config.CreateMapper();

return categories.Select(mapper.Map<SimpleClass>).ToList();

@RGoloubkov
Copy link

I have the same error in VS 2017. Temporary solution with automapper work with simple Count, but in my case i have count of group items, somth like this:
var rows = this.context.data
.Select(r => new
{
....... //no matter
Count = r.Entities.GroupBy( x=>x.name ).Count()
}).ToList();

In this case i have same error: '_outer_Id' with anonymous class too. In VS2015 all work fine.

@ajcvickers
Copy link
Member

@maumar It looks like this could be a dupe of or related to #7811 and is probably also a regression from 1.1.0. As Doug originally reported it there was a query compiler error in 1.1.0 and hence we didn't think it was a regression, but from other comments it seems like there were cases that were working in 1.1.0. I'm putting this in 1.1.2 for now, but feel free to close as a dupe or set for re-triage as appropriate.

@ajcvickers ajcvickers modified the milestones: 1.1.2, 2.0.0 Mar 9, 2017
@RGoloubkov
Copy link

I confirm what in 1.1.0 with VS 2017 all work correct

thiennn added a commit to simplcommerce/SimplCommerce that referenced this issue Mar 9, 2017
@joshmouch
Copy link

I'm getting a similar error but I'm selecting an anonymous type. This broke after upgrade to VS 2017 and EF Core 1.1.1.

@maumar
Copy link
Contributor

maumar commented Mar 14, 2017

Problem was caused by: b8fb258

@maumar
Copy link
Contributor

maumar commented Mar 15, 2017

@joshmouch can you post your query and model? (entities and contents of OnModelCreating method on the DbContext)

@maumar maumar changed the title InvalidOperationException at runtime for simpler version of #6534 query Invalid query produced when projecting subquery that returns a single element (e.g. c.Orders.Count()) Mar 15, 2017
@maumar maumar changed the title Invalid query produced when projecting subquery that returns a single element (e.g. c.Orders.Count()) Invalid query produced when projecting DTO containing subquery that returns a single element Mar 15, 2017
maumar added a commit that referenced this issue Mar 15, 2017
…subquery that returns a single element

Problem was that in the fix for #7033 we force client evaluation on queries that try to bind to parents, when the parent has a client projection.
However, for the case when single element is returned (e.g. cusotmers.Select(c => new DTO { Count = c.Orders.Count() })) we don't need to do client evaluation.
We actually try to merge the subquery into the parent query, but this causes a problem because earlier in the pipeline we assumed that client eval is needed (since parent QM has client projection)

Fix is to be consistent and never try to lift subquery if the parent QM has a client projection. This causes more scenarios to produce N+1 queries, but the proper fix would require a breaking change:
we need additional information passed to the SqlTranslatingExpressionVisitor to know that the subquery that is being visited returns a single value.
@maumar
Copy link
Contributor

maumar commented Mar 15, 2017

Fixed in 8dbcab1

@maumar maumar closed this as completed Mar 15, 2017
@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 Mar 15, 2017
@maumar
Copy link
Contributor

maumar commented Mar 15, 2017

Also opened #7882 to track proper fix in the 2.0.0 that would not introduce unnecessary N+1 queries for those cases.

@paddyfink
Copy link

@maumar When you say fixed, you mean it will be fixed with the next entity framework update? Do you have a date approximatively? Thanks

@maumar
Copy link
Contributor

maumar commented Mar 15, 2017

@paddyfink the fix will be available with the next patch release (1.1.2). Unfortunately we don't have any dates yet. If possible, you should use the workaround, i.e. don't use the DTO, but use anonymous type instead (and then project into DTO in memory):

rather than:

customers.Select(c => new MyDTO { Count = c.Orders.Count() }).ToList();

do:

customers.Select(c => new { Count = c.Orders.Count() }).ToList().Select(r => new MyDTO { Count = r.Count });

If this workaround works for you, you should use it even after the fix is in, as the queries with DTO
we will produce inefficient SQL (rather than simply throwing).

@joshmouch
Copy link

I'd just like to say that this is a pretty huge deal. I don't think it's enough to say "we'll release a fix in 2.0 sometime in the future."
Probably 50% of my queries are broken because of this, or what I think is the same bug I put in this ticket:
#7915.

@szykov
Copy link

szykov commented Mar 17, 2017

@joshmouch It's the open source project, we're not in a situation to push them to do anything. But you can always contribute and make 2.0 release sooner.

@joshmouch
Copy link

@szykov My meaning is that I hope this could be made as part of a bug fix rather than a whole new release. This seems pretty big to me for people migrating from existing EF queries.

@szykov
Copy link

szykov commented Mar 17, 2017

@joshmouch as @maumar said they can't fix that bug without changing API. EF supports semantic versioning and breaking change such as changing API means a major change from point of semantic versioning. Because it ruins backward compatibility. Major change means increasing the first number of the version => 2.0.

http://semver.org

@joshmouch
Copy link

joshmouch commented Mar 17, 2017

@maumar I'm just guessing here, but is ticket #7915 the same issue? Is using the "let" statements causing the same sort of client evaluation to be performed as projecting to a DTO does? Will 1.1.2 allow "let" statements to be used again?

@dapalmi
Copy link

dapalmi commented Mar 22, 2017

I have following query with the same error message:

var test = _repository.AggregateQueryable
    .Select(x => x.Items.Any() 
       ? x.Items.GroupBy(y => y.Priority).Select(g => g.Key).ToArray() 
       : new int[0]);

What is the workaround for this?

maumar added a commit that referenced this issue Mar 25, 2017
…ntaining subquery that returns a single element

Problem was that in the fix for #7033 we force client evaluation on queries that try to bind to parents, when the parent has a client projection.
However, for the case when single element is returned (e.g. cusotmers.Select(c => new DTO { Count = c.Orders.Count() })) we don't need to do client evaluation.
We actually try to merge the subquery into the parent query, but this causes a problem because earlier in the pipeline we assumed that client eval is needed (since parent QM has client projection)

Fix is to flow information about query model's StreamedDataInfo into SqlTranslatingExpressionVisitor so that we only client-eval when it's really necessary (i.e. when more than one element is returned from the subquery).
Information is stored in (proper) internal fields as we don't really want to expose this API in any way.
@dvdobrovolskiy
Copy link

Seems like I also met same error when trying to get some aggregated values in subselect

var results = _context.Persons.Select(s => new PersonVM
{
   PersonId = s.PersonId,
   StaffCount = _context.PersonStuff.Include(i => i.Person).Where(w => w.Person.PersonId == s.PersonId).Count(),
   StaffExist = _context.PersonStuff.Include(i => i.Person).Any(w => w.Person.PersonId == s.PersonId),
});

with models

    public class PersonVM
    {
        [Key]
        [Display(Name = "Id")]
        public int PersonId { get; set; }

        public int StaffCount { get; set; }

        public bool StaffExist { get; set; }
    }

    public class Person
    {
        [Key]
        [Display(Name = "Id")]
        public int PersonId { get; set; }

    }

    public class PersonStuff
    {
        [Key]
        [Display(Name = "Id")]
        public int PersonStuffId { get; set; }

        public Person Person { get; set; }
    }

test project if needed
http://static.realgrad.ru/WebApplication2.zip

@dvdobrovolskiy
Copy link

@maumar can you please explain if error I have is related to this error as suggested workaround seems like does not work in one case

_context.Persons.Include(i => i.Level)
.Select(s => new {
PersonId = s.PersonId,
FullName = s.FullName,
DOB = s.DOB,
cnt = _context.CorporatePersons.Include(i => i.Person).Where(a => a.Person.PersonId == s.PersonId).Count(),
});

Error is
System.InvalidCastException: 'Unable to cast object of type '<_GroupJoin>d__264[CETDB.Data.CorporatePerson,CETDB.Data.Person,System.Nullable1[System.Int32],Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor+TransparentIdentifier2[CETDB.Data.CorporatePerson,System.Collections.Generic.IEnumerable1[CETDB.Data.Person]]]' to type 'System.Int32'.'

also

_context.Persons.Include(i => i.Level)
.Select(s => new {
PersonId = s.PersonId,
FullName = s.FullName,
DOB = s.DOB,
isCorporate = _context.CorporatePersons.Include(i=>i.Person).Any(a=>a.Person.PersonId == s.PersonId),
});

generates
InvalidOperationException: Sequence contains no elements

@maumar
Copy link
Contributor

maumar commented Mar 27, 2017

@dvdobrovolskiy the scenario from your first post is indeed the same problem. The proposed workaround should resolve it though (tested with the model you provided). The second issue is different - it's a compile time error, where the issue in question throws at runtime (due to incorrect SQL being generated). Could you file a new issue for this? Please also provide the model used, as it seems to be different (more complex) than the one you provided.

@dvdobrovolskiy
Copy link

New issue #8005

PS
Workaround did help. But First posts is about new project I created to demonstrate issue and I tried to recreate same conditions as my current project. But in my current project (second post and new issue) Workaround do not help me

maumar added a commit that referenced this issue Mar 27, 2017
…ntaining subquery that returns a single element

Problem was that in the fix for #7033 we force client evaluation on queries that try to bind to parents, when the parent has a client projection.
However, for the case when single element is returned (e.g. cusotmers.Select(c => new DTO { Count = c.Orders.Count() })) we don't need to do client evaluation.
We actually try to merge the subquery into the parent query, but this causes a problem because earlier in the pipeline we assumed that client eval is needed (since parent QM has client projection)

Fix is to flow information about query model's StreamedDataInfo into SqlTranslatingExpressionVisitor so that we only client-eval when it's really necessary (i.e. when more than one element is returned from the subquery).
Information is stored in (proper) internal fields as we don't really want to expose this API in any way.
@maumar
Copy link
Contributor

maumar commented Mar 28, 2017

@szykov @joshmouch good news, we did some extra digging around this issue and were able to come up with a different, more functional approach. Once the patch is live, you should be able to use DTOs without drawbacks, just like in 1.1.0. Query from #7915 will also be better, although there will still be N+1 due to other issues (discussed in the bug itself)

@mb2140
Copy link

mb2140 commented Mar 28, 2017

I agree that this is a pretty serious bug - especially considering VS 2017 is a one-way upgrade. Can we grab a nightly build that includes this fix anywhere?

@maumar
Copy link
Contributor

maumar commented Mar 29, 2017

@mb2140 we are planning to provide a feed with the patch fixes, however cureently we don't know when that will be available. For the time being you have to clone the patch repo (https://github.com/aspnet/EntityFramework/tree/rel/1.1.2) and build it manually.

@Eilon
Copy link
Member

Eilon commented Apr 12, 2017

This patch fix is approved. Please follow the normal code review / pull request process and make sure you make the change in the correct branch.

@maumar maumar closed this as completed Apr 12, 2017
@Eilon
Copy link
Member

Eilon commented Apr 19, 2017

Preview builds of this patch fix should be available on the following feeds:

If you have a chance, please try out these preview builds and let us know if you have any feedback!

@dvdobrovolskiy
Copy link

Patch did`nt helped with #8233
Still have grouping issue

@smitpatel
Copy link
Member

@dvdobrovolskiy - The probable fix for #8233 is not in patch and will be released in 2.0.0-preview1

@dvdobrovolskiy
Copy link

Year, may the 10th. Waiting. Thanks!

@andershermansen
Copy link

@Eilon My project was hit by this bug with 1.1.1 so I have have kept it at EfCore 1.1.0.
I tested the preview package of 1.1.2 now (1.1.2-rtm-201704210746), it works great! :)
No more exception

@Eilon
Copy link
Member

Eilon commented Apr 24, 2017

@andershermansen that's great, thank you so much for trying it out!

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