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 #35299 - EF Core InMemory database throws an argument exception on Nullable<>.ToString #35763

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

maumar
Copy link
Contributor

@maumar maumar commented Mar 11, 2025

Problem was that when rewriting the (inmemory) query, sometimes we change the nullability of the expression fragment. (e.g. when accessing a property on an optional entity). We then have a logic to compensate for the change. E.g. when the modified fragment was a caller of a method, we add a null check and only call the method (as non-nullable argument) if the value is not null. This way we can retain the method signature as it was. In 9, we added some exemptions to this logic, e.g. GetValueOrDefault, or Nullable<>.ToString, which don't need the compensation. Problem was that we were matching the ToString method incorrectly, only looking at the method name, so we would also match non-nullable ToString(). Fix is to look at the declaring type of the ToString method as well to make sure it's nullable, otherwise apply the compensation.

Fixes #35299

@maumar maumar requested a review from a team as a code owner March 11, 2025 09:50
@maumar maumar requested review from Copilot and a team and removed request for a team March 11, 2025 09:50

Choose a reason for hiding this comment

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

PR Overview

This PR addresses an issue where the compensation logic was incorrectly applied to non-nullable ToString calls by refining the matching criteria for Nullable.ToString. The changes include updating the method call condition in the expression visitor and adding a new functional test to verify the fix.

  • Updated logic in InMemoryExpressionTranslatingExpressionVisitor to check the declaring type for Nullable.ToString.
  • Added a new functional test in GearsOfWarQueryInMemoryTest to cover the behavior on non-nullable properties.

Reviewed Changes

File Description
test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs Added a functional test to ensure proper handling of ToString on non-nullable properties of an optional entity.
src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs Refined the condition to correctly exclude Nullable.ToString by verifying the method's DeclaringType.

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

Comments suppressed due to low confidence (1)

src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs:891

  • [nitpick] The updated condition for excluding Nullable.ToString now includes a check on DeclaringType, which makes the logic complex. Consider adding inline comments or refactoring this condition into a helper method for better readability and maintainability.
&& !(@object!.Type.IsNullableValueType()
@maumar
Copy link
Contributor Author

maumar commented Mar 11, 2025

added the test to InMemory only - there is a discrepancy in the results for this scenario: in memory returns null (which is what it returned in 8, this change essentially reverts to the 8.0 behavior, fixing the regression we made in 9), whereas relational returns empty string (we append coalesce "") to those queries

@maumar
Copy link
Contributor Author

maumar commented Mar 11, 2025

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@maumar maumar marked this pull request as draft March 11, 2025 17:35
…n on Nullable<>.ToString

Problem was that when rewriting the (inmemory) query, sometimes we change the nullability of the expression fragment. (e.g. when accessing a property on an optional entity). We then have a logic to compensate for the change. E.g. when the modified fragment was a caller of a method, we add a null check and only call the method (as non-nullable argument) if the value is not null. This way we can retain the method signature as it was. In 9, we added some exemptions to this logic, e.g. `GetValueOrDefault`, or `Nullable<>.ToString`, which don't need the compensation. Problem was that we were matching the ToString method incorrectly, only looking at the method name, so we would also match non-nullable ToString(). Fix is to look at the declaring type of the ToString method as well to make sure it's nullable<T>, otherwise apply the compensation.

Fixes #35299
@maumar maumar marked this pull request as ready for review March 12, 2025 05:08
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.

EF Core InMemory database throws an argument exception on Nullable<>.ToString
1 participant