-
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
Add an IncludeInner method #24955
Comments
Rather than a special IncludeInner operator, users could express this via something like:
This current version generates an OUTER JOIN and an EXISTS subquery, but maybe we could identify this pattern and generate an INNER JOIN instead... /cc @smitpatel Regardless, @GertArnold there are various other scenarios where EF Core already generates an INNER JOIN, based on the precise situation and model configuration. Whether EF generates an OUTER or INNER join generally shouldn't be something the user specifies directly, but is rather inferred from EF based on the query and the model. |
Instead of going into pattern matching, we could have metadata API to configure that collection will always have 1 child. Just like how we have API to market that principal to dependent reference navigation is required. (i.e. Child will always exist for the given principal). This will be useful for any nav expansion not just include. Apart from that, users are free to write LINQ when their joins contain additional information not configured in metadata manually using existing LINQ operators to generate inner/outer join as needed. |
We discussed this in triage. As @smitpatel said, we should consider expanding optional/required dependents in metadata to better optimize Include for the model. @AndriySvyryd @smitpatel I can't find any existing issue to cover this. In addition, we should have an issue on the backlog to support generating more efficient queries for cases for queries that assert requiredness without that being in the model. |
I went to github asking for the same as @GertArnold. I would be perfectly ok with Regarding model metadata: OK, but I still want to be able to to force inner join when writing query. I would like to be able to write query like: SELECT * FROM Parents p INNER JOIN Children c ON p.Id = c.ParentId
WHERE c.Type = 1 which would return ctx.Parents.Include(b => b.Children.Where(p => p.Type = 1)).Where(p => p.Children.Any()).ToList(); Use CaseI needed only parents with specific children in my OData endpoint and I find it difficult to with RawSql / DB View, because how do I apply Skip/Take or Count() at Parents' level? I've ended up with two options:
|
You can always write a query with whatever joins you need without using navigations directly if you want to deviate from the configured metadata in the model. |
@smitpatel: if you mean this, then no, because it returns parents x children, not parents with children. I need |
I have to upvote the original suggestion and disagree with the idea that optional/required metadata should decide whether inner or outer joins should be used. You don't define foreign keys as an "inner foreign keys" or "outer foreign keys". Foreign keys are supposed to allow you to write both inner and outer joins depending on the scenario. Currently you have to write complex LINQ queries to get an inner join on a many to many relationship. Whereas if you were writing raw SQL you would just have to replace a single keyword with LEFT or INNER. |
Hey @smitpatel, do you have any update about this problem? The current status is either slow SQL or RAW SQL (as Liero explained well), and I can't see how the metadata would help as it does depend of what I want to do with one Include specifically, not all the Includes on a navigation property. |
I happened to stumble upon a similar problem. The way I got around this was to reverse my query, i.e. instead of querying the parent and including the child, I queried the child and included the parent, and then finally selecting the parent from the child and doing a distinct. Something like:
This produces the desired query with |
@1nfected Yes, that's a work-around. Note that the child collections aren't marked as loaded which is awkward when lazy loading is enabled: it should be disabled temporarily when accessing the collections. Also, when using |
The relational database model doesn't have a concept of mandatory children since ownership is defined by a foreign key in a child relation. As a consequence, in SQL,
Include
always has to translate toOUTER JOIN
because there's no formal language to configure the association as1-1..n
(certainly not vendor-independent). It's always1-0..n
. A statement likeshould, of course, return all parent records, not just the ones with children. Hence the outer join.
There are three reasons why this
OUTER JOIN
may not always be desired.INNER JOIN
because there is foreknowledge of the database content. (Which in such cases will be enforced by client-side validation).Include
children and at the same time filter only parents with children. Here,INNER JOIN
is better thanOUTER JOIN
+ a predicate. Again, in plain SQL that would be a no-brainer.INNER JOIN
s may perform significantly better thanOUTER JOIN
s, esp. in more complex queries, it would be useful for developers to have control over the type of join EF will execute.So I wonder if there is a case for adding an
IncludeInner
(+ThenIncludeInner
) method that does exactly that: always translate to an inner join?This will also work with filtered includes. It can also be made to work with split queries: one query without results for a parent will remove the parent from the end result.
It is expected from developers to have sufficient knowledge of SQL to understand how
INNER
andOUTER
joins work an how they affect one another, esp. how oneINNER JOIN
can turn previousOUTER JOIN
s into de-factoINNER
joins.The text was updated successfully, but these errors were encountered: