-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Count() does not equal number of results if included navigation property does not match query filter #19649
Comments
|
I think I have the same problem #19764 |
discrepancy comes from the fact that when navigation rewrite processes Count, we have optimization in place which just applies count on the source directly, completely ignoring pending selector. Assumption is that the count should be the same. However, if the projection contains required navigation, and the entity that is on the other side of that navigation is filtered out by query filter, we remove the source to maintain referential integrity. |
Filed #19801 to introduce model validation for this case as it seems counter-intuitive and can lead to issues. |
per design discussion, added a model validation phase that warns against using required navigations where required side has the query filter and the optional side doesn't (tracked by #19801). Also improved docs to illustrate the issue, closing. |
I have same problem too. I get this problem with these versions: Is there any roadmap to solve this issue? -- Update -- |
@hakanaltindis please open a new issue with a minimal, runnable code sample that shows the problem occurring. |
I opened new issue |
@hakanaltindis sorry, I should have read this issue more thoroughly before answering you. When running your code repro in #29599, I'm seeing the proper warning emitted:
This points to this doc section, which explains what's going on and provides pretty much the same code sample as your own. So everything seems to be working as it was designed to - or are you seeing something different? |
Hi @roji , I read this topic before. And it says you may encounter unexpected results because global query filter is included in automatically. But I am aware of it and my all results come my expected. The point what I do not get that Why does EF core not add the global query filters to get number of records. |
I'm not following... Your posted SQL in #29599 (comment) clearly shows |
When I call this LINQ But when I call this LINQ Select a.id, a.Name, c.Name
From Activity as a
Inner Join Customer As c On (a.CustomerId = c.Id)
Where c.IsDeleted = false What I try to say that If I want to get records/rows, everything works perfect. But If I just want to get number of records, it is not working correctly. |
@hakanaltindis that behavior - and the discrepancy between Count() and ToList() - is explained above. I agree it's somewhat odd, but that's why we have the warning I referred to above. |
@roji yes, it is odd. So do you have any plan to fix it? Because this odd prevents consistency. What is your recommendation? I understand we can not use EF Core for Enterprise applications from what you say. |
That is definitely not what I'm saying.
In short, although I agree the behavior is odd, there doesn't seem to be an obvious correct behavior here, and some users would complain no matter what we do. This is why the warning (and documentation) exists, to alert people to this behavior. Note that you can always explicitly ask to filter as you wish by adding a Where clause before the filter (instead of the Include) - that should give you the results you want. |
I am really trying to understand you. Sometimes your thoughts about // Numbers are related with my example.
_dbContext.Activities.Include(a => a.Customer).Count(); // returns 11
_dbContext.Activities.Include(a => a.Customer).ToList().Count(); // returns 9 But you specified how odd this behavior. And I don't want to prolong this topic. So be it. :) I try to find a workaround for my case. Thank you for your responses. |
@hakanaltindis we had a discussion around this, I've opened #29645 to track possibly changing our behavior. |
Thank you, @roji . I will follow this topic very closely. 👍 🙂 |
If a query selects a property from a related entity reached by a required navigation property, but the related entity is excluded by a query filter,
query.Count()
will not matchquery.ToList().Count
. Actualizing the results withToList()
will exclude the row from its results, as the related entity is filtered out, butCount()
does not exclude the result even though the query is selecting a member of the navigation property explicitly.We use this functionality to build search results one page at a time: build a filtered and projected
IQueryable<TEntity> query
, usequery.Count()
to get the total number of results, thenquery.OrderBy(orderBy).Skip(skip).Take(take).ToList()
to resolve a subset of the results. Our actual implementation has a much more complicated projection thanks to AutoMapper, but as recently as EF Core 2.2.6, callingCount()
on the queryable returned the same cardinality as the result set (indeed, the code generated for SQL Server has the same FROM and JOIN clauses and differs only in the SELECT lists).Steps to reproduce
The code above uses InMemory for brevity, but Sqlite exhibits the same behavior and generates the following query for
query.ToList()
, returning no rows:And for
query.Count()
, returning a count of 1:I also noticed that, if I used
.Include(e => e.RelatedEntity)
instead of.Select(e => e.RelatedEntity.SomeProperty)
in the test above, EF Core 2.2.6 and 3.1.1 both return 1 forquery.Count()
and 0 forquery.ToList().Count
. This is not currently causing us issues, but it looks similar yet behaves consistently across versions, so I thought it would be worth mentioning.Further technical details
EF Core version: 3.1.1
Database provider: Microsoft.EntityFrameworkCore.InMemory 3.1.1, Microsoft.EntityFrameworkCore.Sqlite 3.1.1, Microsoft.EntityFrameworkCore.SqlServer 3.1.1
Target framework: .NET Core 3.1
Operating system: Windows 10
IDE: Visual Studio 2019 16.4.2
The text was updated successfully, but these errors were encountered: