-
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
efcore6 produces wrong SELECT SQL when Where/OrderBy clauses are applied to Owned properties followed by .Take() #26592
Comments
Unrelated note - the SQL generated in 5.0 caused unnecessary join with |
Expanding other navigations causes initial SelectExpression to change which causes earlier expanded owned navigations to be incorrect. This won't be an easy fix. |
… generated Issue: Expanding owned navigations in relational falls into 3 categories - Collection navigation - which always generates a subquery. The predicate is generated in LINQ to allow mutation of outer SelectExpression - Reference navigation sharing table - which picks column from same table without needing to add additional join. This only mutate the projection list for SelectExpression at subquery level - Reference navigation mapped to separate table - which generates additional joins. Generating join can cause push down on outer SelectExpression if it has facets (e.g. limit/offset). This pushdown causes owned expansion from category 2 to be outdated and invalid SQL since they get pushed down to subquery. While their relevant entity projection is updated inside SelectExpression we already inlined older object in the tree at this point. In order to avoid issue with outdated owned expansion, we defer actual inline-ing while processing owned navigations so that all navigations are expanded (causing any mutation on SelectExpression) before we inline values. This PR introduces DeferredOwnedExpansionExpression which remembers the source projection binding to SelectExpression (which will remain accurate through pushdown), and navigation chain to traverse entity projections to reach entity shaper for final owned navigation. This way, we get up-to-date information from SelectExpression after all joins are generated. We also find updated entity projection through binding after we generate a join if pushdown was required. Resolves #26592 The issue was also present in 5.0 release causing non-performant SQL rather than invalid SQL. During 5.0 we expanded owned navigations again while during client eval phase (which happens in customer scenario due to include). This caused to earlier owned reference to have correct columns. Though the entity projection for owner was changed due to pushdown so we didn't add latter reference navigation binding in correct entity projection causing us to expand it again during 2nd pass. The exact same issue doesn't occur for InMemory provider (due to slightly different implementation) though we should also make InMemory provider work this way, which we can do in 7.0.
… generated Issue: Expanding owned navigations in relational falls into 3 categories - Collection navigation - which always generates a subquery. The predicate is generated in LINQ to allow mutation of outer SelectExpression - Reference navigation sharing table - which picks column from same table without needing to add additional join. This only mutate the projection list for SelectExpression at subquery level - Reference navigation mapped to separate table - which generates additional joins. Generating join can cause push down on outer SelectExpression if it has facets (e.g. limit/offset). This pushdown causes owned expansion from category 2 to be outdated and invalid SQL since they get pushed down to subquery. While their relevant entity projection is updated inside SelectExpression we already inlined older object in the tree at this point. In order to avoid issue with outdated owned expansion, we defer actual inline-ing while processing owned navigations so that all navigations are expanded (causing any mutation on SelectExpression) before we inline values. This PR introduces DeferredOwnedExpansionExpression which remembers the source projection binding to SelectExpression (which will remain accurate through pushdown), and navigation chain to traverse entity projections to reach entity shaper for final owned navigation. This way, we get up-to-date information from SelectExpression after all joins are generated. We also find updated entity projection through binding after we generate a join if pushdown was required. Resolves #26592 The issue was also present in 5.0 release causing non-performant SQL rather than invalid SQL. During 5.0 we expanded owned navigations again while during client eval phase (which happens in customer scenario due to include). This caused to earlier owned reference to have correct columns. Though the entity projection for owner was changed due to pushdown so we didn't add latter reference navigation binding in correct entity projection causing us to expand it again during 2nd pass. The exact same issue doesn't occur for InMemory provider (due to slightly different implementation) though we should also make InMemory provider work this way, which we can do in 7.0.
… generated Issue: Expanding owned navigations in relational falls into 3 categories - Collection navigation - which always generates a subquery. The predicate is generated in LINQ to allow mutation of outer SelectExpression - Reference navigation sharing table - which picks column from same table without needing to add additional join. This only mutate the projection list for SelectExpression at subquery level - Reference navigation mapped to separate table - which generates additional joins. Generating join can cause push down on outer SelectExpression if it has facets (e.g. limit/offset). This pushdown causes owned expansion from category 2 to be outdated and invalid SQL since they get pushed down to subquery. While their relevant entity projection is updated inside SelectExpression we already inlined older object in the tree at this point. In order to avoid issue with outdated owned expansion, we defer actual inline-ing while processing owned navigations so that all navigations are expanded (causing any mutation on SelectExpression) before we inline values. This PR introduces DeferredOwnedExpansionExpression which remembers the source projection binding to SelectExpression (which will remain accurate through pushdown), and navigation chain to traverse entity projections to reach entity shaper for final owned navigation. This way, we get up-to-date information from SelectExpression after all joins are generated. We also find updated entity projection through binding after we generate a join if pushdown was required. Resolves #26592 The issue was also present in 5.0 release causing non-performant SQL rather than invalid SQL. During 5.0 we expanded owned navigations again while during client eval phase (which happens in customer scenario due to include). This caused to earlier owned reference to have correct columns. Though the entity projection for owner was changed due to pushdown so we didn't add latter reference navigation binding in correct entity projection causing us to expand it again during 2nd pass. The exact same issue doesn't occur for InMemory provider (due to slightly different implementation) though we should also make InMemory provider work this way, which we can do in 7.0.
… generated Issue: Expanding owned navigations in relational falls into 3 categories - Collection navigation - which always generates a subquery. The predicate is generated in LINQ to allow mutation of outer SelectExpression - Reference navigation sharing table - which picks column from same table without needing to add additional join. This only mutate the projection list for SelectExpression at subquery level - Reference navigation mapped to separate table - which generates additional joins. Generating join can cause push down on outer SelectExpression if it has facets (e.g. limit/offset). This pushdown causes owned expansion from category 2 to be outdated and invalid SQL since they get pushed down to subquery. While their relevant entity projection is updated inside SelectExpression we already inlined older object in the tree at this point. In order to avoid issue with outdated owned expansion, we defer actual inline-ing while processing owned navigations so that all navigations are expanded (causing any mutation on SelectExpression) before we inline values. This PR introduces DeferredOwnedExpansionExpression which remembers the source projection binding to SelectExpression (which will remain accurate through pushdown), and navigation chain to traverse entity projections to reach entity shaper for final owned navigation. This way, we get up-to-date information from SelectExpression after all joins are generated. We also find updated entity projection through binding after we generate a join if pushdown was required. Resolves #26592 The issue was also present in 5.0 release causing non-performant SQL rather than invalid SQL. During 5.0 we expanded owned navigations again while during client eval phase (which happens in customer scenario due to include). This caused to earlier owned reference to have correct columns. Though the entity projection for owner was changed due to pushdown so we didn't add latter reference navigation binding in correct entity projection causing us to expand it again during 2nd pass. The exact same issue doesn't occur for InMemory provider (due to slightly different implementation) though we should also make InMemory provider work this way, which we can do in 7.0.
… generated Issue: Expanding owned navigations in relational falls into 3 categories - Collection navigation - which always generates a subquery. The predicate is generated in LINQ to allow mutation of outer SelectExpression - Reference navigation sharing table - which picks column from same table without needing to add additional join. This only mutate the projection list for SelectExpression at subquery level - Reference navigation mapped to separate table - which generates additional joins. Generating join can cause push down on outer SelectExpression if it has facets (e.g. limit/offset). This pushdown causes owned expansion from category 2 to be outdated and invalid SQL since they get pushed down to subquery. While their relevant entity projection is updated inside SelectExpression we already inlined older object in the tree at this point. In order to avoid issue with outdated owned expansion, we defer actual inline-ing while processing owned navigations so that all navigations are expanded (causing any mutation on SelectExpression) before we inline values. This PR introduces DeferredOwnedExpansionExpression which remembers the source projection binding to SelectExpression (which will remain accurate through pushdown), and navigation chain to traverse entity projections to reach entity shaper for final owned navigation. This way, we get up-to-date information from SelectExpression after all joins are generated. We also find updated entity projection through binding after we generate a join if pushdown was required. Resolves #26592 The issue was also present in 5.0 release causing non-performant SQL rather than invalid SQL. During 5.0 we expanded owned navigations again while during client eval phase (which happens in customer scenario due to include). This caused to earlier owned reference to have correct columns. Though the entity projection for owner was changed due to pushdown so we didn't add latter reference navigation binding in correct entity projection causing us to expand it again during 2nd pass. The exact same issue doesn't occur for InMemory provider (due to slightly different implementation) though we should also make InMemory provider work this way, submitting in a different PR in case we need to cherry-pick this for patch.
Due to fix being on riskier side, we are fixing this issue in 7.0 release (& nightly builds). We will determine to patch this in future if we get more customers hitting this. |
… generated (#26641) Issue: Expanding owned navigations in relational falls into 3 categories - Collection navigation - which always generates a subquery. The predicate is generated in LINQ to allow mutation of outer SelectExpression - Reference navigation sharing table - which picks column from same table without needing to add additional join. This only mutate the projection list for SelectExpression at subquery level - Reference navigation mapped to separate table - which generates additional joins. Generating join can cause push down on outer SelectExpression if it has facets (e.g. limit/offset). This pushdown causes owned expansion from category 2 to be outdated and invalid SQL since they get pushed down to subquery. While their relevant entity projection is updated inside SelectExpression we already inlined older object in the tree at this point. In order to avoid issue with outdated owned expansion, we defer actual inline-ing while processing owned navigations so that all navigations are expanded (causing any mutation on SelectExpression) before we inline values. This PR introduces DeferredOwnedExpansionExpression which remembers the source projection binding to SelectExpression (which will remain accurate through pushdown), and navigation chain to traverse entity projections to reach entity shaper for final owned navigation. This way, we get up-to-date information from SelectExpression after all joins are generated. We also find updated entity projection through binding after we generate a join if pushdown was required. Resolves #26592 The issue was also present in 5.0 release causing non-performant SQL rather than invalid SQL. During 5.0 we expanded owned navigations again while during client eval phase (which happens in customer scenario due to include). This caused to earlier owned reference to have correct columns. Though the entity projection for owner was changed due to pushdown so we didn't add latter reference navigation binding in correct entity projection causing us to expand it again during 2nd pass. The exact same issue doesn't occur for InMemory provider (due to slightly different implementation) though we should also make InMemory provider work this way, submitting in a different PR in case we need to cherry-pick this for patch.
We have now hit this issue several times in our app. |
Now two customer reports; re-opening to re-discuss patching. |
Note from triage: @smitpatel Can you open a PR against release/6.0 and we will take this back to Tactics. |
… generated Issue: Expanding owned navigations in relational falls into 3 categories - Collection navigation - which always generates a subquery. The predicate is generated in LINQ to allow mutation of outer SelectExpression - Reference navigation sharing table - which picks column from same table without needing to add additional join. This only mutate the projection list for SelectExpression at subquery level - Reference navigation mapped to separate table - which generates additional joins. Generating join can cause push down on outer SelectExpression if it has facets (e.g. limit/offset). This pushdown causes owned expansion from category 2 to be outdated and invalid SQL since they get pushed down to subquery. While their relevant entity projection is updated inside SelectExpression we already inlined older object in the tree at this point. In order to avoid issue with outdated owned expansion, we defer actual inline-ing while processing owned navigations so that all navigations are expanded (causing any mutation on SelectExpression) before we inline values. This PR introduces DeferredOwnedExpansionExpression which remembers the source projection binding to SelectExpression (which will remain accurate through pushdown), and navigation chain to traverse entity projections to reach entity shaper for final owned navigation. This way, we get up-to-date information from SelectExpression after all joins are generated. We also find updated entity projection through binding after we generate a join if pushdown was required. Resolves #26592 The issue was also present in 5.0 release causing non-performant SQL rather than invalid SQL. During 5.0 we expanded owned navigations again while during client eval phase (which happens in customer scenario due to include). This caused to earlier owned reference to have correct columns. Though the entity projection for owner was changed due to pushdown so we didn't add latter reference navigation binding in correct entity projection causing us to expand it again during 2nd pass. The exact same issue doesn't occur for InMemory provider (due to slightly different implementation) though we should also make InMemory provider work this way, which we can do in 7.0.
Just upgraded an app to 6.0 and am also hitting this issue. |
Happy New Year. I just ran into a similar issue (in 6.0.1) which I'm guessing is related. In short, an entity with 2 owned types - one of which is in an external table - will have the same error as OP when using I have a repo here. If this is unrelated - and a bug - please let me know if you want me to open a separate issue. |
@cdrfenix Please open a new issue and attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate. |
My bad the query was well generated, i just didnt realize it till i checked in the execution plan. |
Hi everyone,
I found a bug in efcore6 that now produces an invalid SELECT statement when filtering/sorting on owned types stored on other tables.
In particular, the bug happens when more than one owned type is linked to an entity and the where clause is applied NOT to the last owned property, followed by a .Take() clause.
Can you please check this behavior? Thanks in advance!
Example
A Company entity that can be either a Customer, a Supplier or both.
Additional Customer data and Supplier data are stored in separate tables with a 1..1 relationship with the Company table.
These tables are configured as Owned properties of Customer:
Mapping:
Executing the following query
will produce the following wrong SQL when using efcore6:
the same query works as expected in efcore5, producing the following valid SQL:
Attached solution
EfCore6Bugs.zip
The solution contains projects targeting .net5.0 with efcore 5.0.12 and .net6.0 with efcore 6.0.0.
The first project contains the DbContext, the second one is a simple unit test.
On test initialization, an
EfCore6Bugs
database will be created on (LocalDb)\MSSQLLocalDB (please customize the connection string inTestDataContext.cs
as needed) applying migrations for the DbContext.Unit tests should all be successful for .net5.0 (efcore5), while EfCore6ClausesOnFirstOwnedFails will fail for .net6.0 (efcore6)
The text was updated successfully, but these errors were encountered: