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

Fix to #28648 - Json/Query: translate element access of a json array #29656

Merged
merged 1 commit into from
Dec 5, 2022

Conversation

maumar
Copy link
Contributor

@maumar maumar commented Nov 23, 2022

Converting indexer over list/array into ElementAt, so that nav expansion understands it and can perform pushown and inject MaterializeCollectionNavigation expression where necessary. In translation phase we recognize the pattern that nav expansion creates and if the root is JsonQueryExpression, we apply collection index over it. JsonQueryExpression path segment now consists of two components - string representing JSON property name and SqlExpression representing collection index (it can be constant, parameter or any arbitrary expression that resolves to int)

Deduplication is heavily restricted currently - we only de-duplicate projections whose additional path consists of JSON property accesses only (no collection indexes allowed). All queries projecting entities that need JSON array access must be set to NoTracking (for now). This is because we don't flow those collection index values into shaper. Instead, the ordinal keys are filled with dummy values, which prohibits us from doing proper change tracking.

Fixes #28648

@maumar maumar requested review from roji and a team November 23, 2022 08:19
@maumar maumar force-pushed the fix28648_do_deduplication_separately branch 8 times, most recently from 517e7c7 to f0daace Compare November 24, 2022 05:40
@maumar maumar force-pushed the fix28648_do_deduplication_separately branch 7 times, most recently from a67d570 to f852a75 Compare November 30, 2022 13:11
@maumar maumar force-pushed the fix28648_do_deduplication_separately branch from f852a75 to 3f1b691 Compare December 2, 2022 04:48
@maumar maumar requested a review from roji December 2, 2022 04:48
@maumar
Copy link
Contributor Author

maumar commented Dec 4, 2022

new version up @roji

Copy link
Member

@roji roji left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, lots of comments but almost all nits. Would prefer we didn't exempt byte[] from the ElementAt normalization though...

src/EFCore.Relational/Query/PathSegment.cs Outdated Show resolved Hide resolved
src/EFCore.Relational/Query/PathSegment.cs Outdated Show resolved Hide resolved
src/EFCore.Relational/Query/PathSegment.cs Outdated Show resolved Hide resolved
var subquery = mcne.Subquery;

if (subquery is MethodCallExpression selectMethodCall
&& selectMethodCall.Method.IsGenericMethod
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can integrate into pattern above (also block below)

// MCNE(JSON_QUERY($[0].Collection))
// MCNE(JSON_QUERY($[0].Collection).AsQueryable())
// MCNE(JSON_QUERY($[0].Collection).Select(xx => xx.Includes())
// MCNE(JSON_QUERY($[0].Collection).AsQueryable().Select(xx => xx.Includes())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also have AsQueryable after the Select? If so that's not handled below (can just do a while loop to unwrap until nothing is left).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't produce those kinds of expressions - we add asqueryable when the collection is List or other Enumerable. So its always either AsQueryable().Select() or just Select(). Of course customers could also write queries like that (but why?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, thanks for clarifying, no problem.

@maumar maumar force-pushed the fix28648_do_deduplication_separately branch 2 times, most recently from 3999868 to 8f76e65 Compare December 5, 2022 09:17
@maumar
Copy link
Contributor Author

maumar commented Dec 5, 2022

new version up @roji

Converting indexer over list/array into ElementAt, so that nav expansion understands it and can perform pushown and inject MaterializeCollectionNavigation expression where necessary.
In translation phase (specifically in ExpandSharedTypeEntities) we recognize the pattern that nav expansion creates and if the root is JsonQueryExpression, we apply collection index over it.
JsonQueryExpression path segment now consists of two components - string representing JSON property name and SqlExpression representing collection index (it can be constant, parameter or any arbitrary expression that resolves to int)

Deduplication is heavily restricted currently - we only de-duplicate projections whose additional path consists of JSON property accesses only (no collection indexes allowed).
All queries projecting entities that need JSON array access must be set to NoTracking (for now). This is because we don't flow those collection index values into shaper. Instead, the ordinal keys are filled with dummy values, which prohibits us from doing proper change tracking.

Fixes #28648
@maumar maumar force-pushed the fix28648_do_deduplication_separately branch from 8f76e65 to 94be38c Compare December 5, 2022 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Json/Query: translate element access of a json array
3 participants