Conversation
…returns null Co-authored-by: roji <1862641+roji@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR targets a SQL Server–specific crash in SqlServerStringMethodTranslator.TranslateIndexOf when no type mapping can be inferred (e.g., casted expressions), and adds coverage for double-cast string operations across relational providers.
Changes:
- Adjust
TranslateIndexOfto avoid dereferencing a null-inferred type mapping. - Add relational-spec tests for
IndexOf/Replaceover double-cast non-string columns. - Add SQL baselines for the new tests in SQL Server and SQLite functional test suites.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/EFCore.SqlServer/Query/Internal/Translators/SqlServerStringMethodTranslator.cs | Avoids a null dereference when inferred type mapping is missing during IndexOf translation. |
| test/EFCore.Relational.Specification.Tests/Query/Translations/StringTranslationsRelationalTestBase.cs | Introduces new relational-spec test cases for double-cast IndexOf/Replace. |
| test/EFCore.SqlServer.FunctionalTests/Query/Translations/StringTranslationsSqlServerTest.cs | Adds SQL Server baselines for the new relational-spec tests. |
| test/EFCore.Sqlite.FunctionalTests/Query/Translations/StringTranslationsSqliteTest.cs | Adds SQLite baselines for the new relational-spec tests. |
You can also share your feedback on Copilot code review. Take the survey.
src/EFCore.SqlServer/Query/Internal/Translators/SqlServerStringMethodTranslator.cs
Outdated
Show resolved
Hide resolved
...re.Relational.Specification.Tests/Query/Translations/StringTranslationsRelationalTestBase.cs
Outdated
Show resolved
Hide resolved
test/EFCore.SqlServer.FunctionalTests/Query/Translations/StringTranslationsSqlServerTest.cs
Outdated
Show resolved
Hide resolved
test/EFCore.Sqlite.FunctionalTests/Query/Translations/StringTranslationsSqliteTest.cs
Outdated
Show resolved
Hide resolved
…ping fallback - Use ApplyDefaultTypeMapping fallback when InferTypeMapping returns null, ensuring the nvarchar(max)/varchar(max) branch is correctly taken for CHARINDEX return type decisions. - Parameterize the IndexOf test pattern to force parameterization, which exercises the code path where InferTypeMapping returns null. - Update SQL baselines to match parameterized form. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes a SQL Server–specific NullReferenceException in SqlServerStringMethodTranslator.TranslateIndexOf when type mapping inference returns null for double-casted non-string expressions, and adds coverage to prevent regressions across providers.
Changes:
- Ensure
TranslateIndexOfalways has a non-null string type mapping by falling back toApplyDefaultTypeMapping(instance). - Add relational-spec tests covering
IndexOfandReplaceover((string)(object)b.Int)patterns. - Add SQL baseline assertions for the new tests in both SQL Server and SQLite functional test suites.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/EFCore.SqlServer/Query/Internal/Translators/SqlServerStringMethodTranslator.cs | Prevents NRE in SQL Server IndexOf translation by guaranteeing a type mapping is available. |
| test/EFCore.Relational.Specification.Tests/Query/Translations/StringTranslationsRelationalTestBase.cs | Adds new relational tests for double-cast IndexOf and Replace scenarios. |
| test/EFCore.SqlServer.FunctionalTests/Query/Translations/StringTranslationsSqlServerTest.cs | Adds SQL Server baselines for the new relational tests. |
| test/EFCore.Sqlite.FunctionalTests/Query/Translations/StringTranslationsSqliteTest.cs | Adds SQLite baselines for the new relational tests. |
Comments suppressed due to low confidence (1)
src/EFCore.SqlServer/Query/Internal/Translators/SqlServerStringMethodTranslator.cs:228
ApplyDefaultTypeMapping(instance)is called only to extractTypeMapping, and theninstanceis type-mapped again a few lines later. Consider assigninginstance = sqlExpressionFactory.ApplyDefaultTypeMapping(instance)!;first and then usinginstance.TypeMapping!asstringTypeMappingto avoid redundant expression rewriting (and to ensure any nested object-convert unwrapping applies to the instance you later use).
var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, searchExpression)
?? sqlExpressionFactory.ApplyDefaultTypeMapping(instance)!.TypeMapping!;
searchExpression = sqlExpressionFactory.ApplyTypeMapping(
searchExpression, searchExpression.Type == typeof(char) ? CharTypeMapping.Default : stringTypeMapping);
instance = sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping);
You can also share your feedback on Copilot code review. Take the survey.
TranslateIndexOfin the SQL Server provider crashes with aNullReferenceExceptionwhenExpressionExtensions.InferTypeMapping()returnsnull— which occurs when neither the instance nor the search expression has a type mapping assigned, e.g. when using a value-converter property with a double cast:The crash is SQL Server–specific:
TranslateIndexOfdereferences the type mapping to check whether the store type isnvarchar(max)/varchar(max)(to pickbigintvsintas the CHARINDEX return type), while other providers passnullthrough toApplyTypeMappingwhich handles it gracefully.Changes
SqlServerStringMethodTranslator): Remove the null-forgiving!fromInferTypeMappingand use?.StoreType— when the type mapping is unknown we fall through to theelsebranch returningint, a safe default.StringTranslationsRelationalTestBase): AddIndexOf_with_non_string_column_using_double_castandReplace_with_non_string_column_using_double_casttests (the(string)(object)b.Intpattern) with SQL baseline assertions for both SQL Server and SQLite.Original prompt
This section details on the original issue you should resolve
<issue_title>IndexOf translation throws NullReferenceException for casted parameters</issue_title>
<issue_description>Related #17389
I have a
Dictionary<string, string>property with a value converter to astringAnd if I have a query like this:
it throws a
NullReferenceException:Generally, if
ExpressionExtensions.InferTypeMappingreturns null here:efcore/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerStringMethodTranslator.cs
Line 223 in 8bf0f7f
no default type mapping is created/retrieved, and it's not null-checked</issue_description>
Comments on the Issue (you are @copilot in this section)
@roji # AI TriageThe below is an AI-generated analysis and may contain inaccuracies.
Analysis
Confirmed bug. The
NullReferenceExceptionoccurs inSqlServerStringMethodTranslator.TranslateIndexOfwhenExpressionExtensions.InferTypeMapping()returnsnull. This happens because neitherinstancenorsearchExpressionhas aTypeMappingassigned — which can occur when expressions involve casts like((string)(object)s.Parameters).At line 223, the null-forgiving operator
!suppresses the compiler warning, but the value is still null at runtime. The crash occurs at line 242 when accessingstringTypeMapping.StoreType.The same pattern also exists in
TranslateReplace()in the same file (line 162), which is likely also vulnerable.Not a regression — the bug reproduces on both EF Core 8.0.13 and 9.0.3. The SQLite provider does not crash for the same query (it passes
nulltype mapping through toApplyTypeMapping, which handles it gracefully).The bug is SQL Server–specific because
TranslateIndexOfdereferences the type mapping to checkStoreTypefornvarchar(max)/varchar(max)to decide betweenCHARINDEXreturninglongvsint.Still reproduces on current
main.Possible duplicates
No exact duplicates found. Related issue: #17389 (same cast pattern with
EF.Functions.Like, fixed in 3.1.0).Minimal repro
Throws:
📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.