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

QueryRewrite: when comparing entity with composite key to null, only check it's first key property, rather than all of them #15080

Closed
maumar opened this issue Mar 19, 2019 · 11 comments · Fixed by #20447
Assignees
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. punted-for-3.0 type-enhancement
Milestone

Comments

@maumar
Copy link
Contributor

maumar commented Mar 19, 2019

Query:

from g1 in gs
join g2 in gs on g1.HasSoulPatch equals true into grouping
from g2 in grouping.DefaultIfEmpty()
orderby g2.Nickname
select g2 != null
  ? new
  {
	  g2.Nickname,
	  Five = 5
  }
  : null

Expected:

SELECT CASE
    WHEN [t].[Nickname] IS NOT NULL
    THEN CAST(1 AS bit) ELSE CAST(0 AS bit)
END, [t].[Nickname]
FROM [Gears] AS [g1]
LEFT JOIN (
    SELECT [g2].*
    FROM [Gears] AS [g2]
    WHERE [g2].[Discriminator] IN (N'Officer', N'Gear')
) AS [t] ON [g1].[HasSoulPatch] = CAST(1 AS bit)
WHERE [g1].[Discriminator] IN (N'Officer', N'Gear')
ORDER BY [t].[Nickname]

current:

SELECT CASE
    WHEN [t].[Nickname] IS NOT NULL OR [t].[SquadId] IS NOT NULL
    THEN CAST(1 AS bit) ELSE CAST(0 AS bit)
END, [t].[Nickname]
FROM [Gears] AS [g1]
LEFT JOIN (
    SELECT [g2].*
    FROM [Gears] AS [g2]
    WHERE [g2].[Discriminator] IN (N'Officer', N'Gear')
) AS [t] ON [g1].[HasSoulPatch] = CAST(1 AS bit)
WHERE [g1].[Discriminator] IN (N'Officer', N'Gear')
ORDER BY [t].[Nickname]");

Tests affected:
Select_null_propagation_negative4
Select_null_propagation_negative5

@ajcvickers
Copy link
Member

@maumar What if one key value is null and the other is non-null? This should be treated as a null key, but the first property may not be null.

@smitpatel
Copy link
Contributor

@ajcvickers - We may have code in place right now which checks only first null key rather than all of them. Since none of the key should be null if stored to database by EF. Is there any incorrect assumption here?

@ajcvickers
Copy link
Member

@smitpatel If any part of a composite key is null, then the whole key is considered null. So I think the assumption is correct.

@smitpatel
Copy link
Contributor

So you need to tell us what is correct query for above linq. In current source code, we do generate expected SQL. But it is just checking first property being not null.

@ajcvickers
Copy link
Member

@smitpatel If the first value is null => key is null. If the first value is non-null => we don't know if the key is null or not. So we can't "only check its first property" but we can short-circuit the decision as soon as we find a null value. If that's what we're doing already, then fine. If that's what we're going to do, then fine. The issue filed doesn't say that. It says we only need to check the value of one property, and that's not fine.

@smitpatel
Copy link
Contributor

The current SQL only checks first property being non null when translating entity is non-null.

@smitpatel
Copy link
Contributor

So it's a bug in entity equality rewrite. Bump priority?

@ajcvickers
Copy link
Member

Re-triage.

@ajcvickers ajcvickers removed this from the Backlog milestone Mar 16, 2020
@ajcvickers ajcvickers assigned smitpatel and unassigned roji Mar 20, 2020
@ajcvickers ajcvickers added this to the 5.0.0 milestone Mar 20, 2020
@ajcvickers
Copy link
Member

See #20164

@smitpatel
Copy link
Contributor

// When comparing an entity to null, it's sufficient to simply compare its first primary key column to null.
// (this is also why we can do it even over a subquery with a composite key)
return Expression.MakeBinary(
equality ? ExpressionType.Equal : ExpressionType.NotEqual,
CreatePropertyAccessExpression(nonNullExpression, keyProperties[0]),
Expression.Constant(null));
}

@smitpatel smitpatel added closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. and removed needs-design labels Mar 28, 2020
@smitpatel
Copy link
Contributor

Following @ajcvickers statement
Implemented behavior:

  • If any part of composite key is null then key is null.
  • If comparing entity with null then check if "any" key value is null.
  • If comparing entity with non-null then check if "all" key values are non null.

please review @ajcvickers @AndriySvyryd

smitpatel added a commit that referenced this issue Mar 28, 2020
Resolves #15080
Implemented behavior:
- If any part of composite key is null then key is null.
- If comparing entity with null then check if "any" key value is null.
- If comparing entity with non-null then check if "all" key values are non null.

Resolves #20344
Resolves #19431
Resolves #13568
Resolves #13655
Since we already convert property access to nullable, if entity from client is null, make key value as null.

Resolves #19676
Clr type mismatch between proxy type and entity type is ignored.

Resolves #20164
Rewrites entity equality during translation

Part of #18923
smitpatel added a commit that referenced this issue Mar 28, 2020
Resolves #15080
Implemented behavior:
- If any part of composite key is null then key is null.
- If comparing entity with null then check if "any" key value is null.
- If comparing entity with non-null then check if "all" key values are non null.

Resolves #20344
Resolves #19431
Resolves #13568
Resolves #13655
Since we already convert property access to nullable, if entity from client is null, make key value as null.

Resolves #19676
Clr type mismatch between proxy type and entity type is ignored.

Resolves #20164
Rewrites entity equality during translation

Part of #18923
smitpatel added a commit that referenced this issue Mar 28, 2020
Resolves #15080
Implemented behavior:
- If any part of composite key is null then key is null.
- If comparing entity with null then check if "any" key value is null.
- If comparing entity with non-null then check if "all" key values are non null.

Resolves #20344
Resolves #19431
Resolves #13568
Resolves #13655
Since we already convert property access to nullable, if entity from client is null, make key value as null.

Resolves #19676
Clr type mismatch between proxy type and entity type is ignored.

Resolves #20164
Rewrites entity equality during translation

Part of #18923
smitpatel added a commit that referenced this issue Mar 31, 2020
Resolves #15080
Implemented behavior:
- If any part of composite key is null then key is null.
- If comparing entity with null then check if "any" key value is null.
- If comparing entity with non-null then check if "all" key values are non null.

Resolves #20344
Resolves #19431
Resolves #13568
Resolves #13655
Since we already convert property access to nullable, if entity from client is null, make key value as null.

Resolves #19676
Clr type mismatch between proxy type and entity type is ignored.

Resolves #20164
Rewrites entity equality during translation

Part of #18923
smitpatel added a commit that referenced this issue Mar 31, 2020
Resolves #15080
Implemented behavior:
- If any part of composite key is null then key is null.
- If comparing entity with null then check if "any" key value is null.
- If comparing entity with non-null then check if "all" key values are non null.

Resolves #20344
Resolves #19431
Resolves #13568
Resolves #13655
Since we already convert property access to nullable, if entity from client is null, make key value as null.

Resolves #19676
Clr type mismatch between proxy type and entity type is ignored.

Resolves #20164
Rewrites entity equality during translation

Part of #18923
@ajcvickers ajcvickers modified the milestones: 5.0.0, 5.0.0-preview3 Mar 31, 2020
@smitpatel smitpatel modified the milestones: 5.0.0-preview3, 5.0.0 Apr 1, 2020
smitpatel added a commit that referenced this issue Apr 6, 2020
Extends fix for #15080 to navigation expansion too where we check for outerKey != null before correlation predicate.
smitpatel added a commit that referenced this issue Apr 7, 2020
Extends fix for #15080 to navigation expansion too where we check for outerKey != null before correlation predicate.
@ajcvickers ajcvickers modified the milestones: 5.0.0, 5.0.0-preview4 Apr 20, 2020
@ajcvickers ajcvickers modified the milestones: 5.0.0-preview4, 5.0.0 Nov 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. punted-for-3.0 type-enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants