Skip to content

Translate List<T>.Exists to Queryable.Any#38226

Open
m-x-shokhzod wants to merge 3 commits intodotnet:mainfrom
m-x-shokhzod:feat/translate-list-exists
Open

Translate List<T>.Exists to Queryable.Any#38226
m-x-shokhzod wants to merge 3 commits intodotnet:mainfrom
m-x-shokhzod:feat/translate-list-exists

Conversation

@m-x-shokhzod
Copy link
Copy Markdown
Contributor

@m-x-shokhzod m-x-shokhzod commented May 5, 2026

Rewrites List<T>.Exists(predicate) to AsQueryable().Any(predicate) in QueryableMethodNormalizingExpressionVisitor, mirroring the existing ICollection<T>.Contains conversion. The Predicate<T> lambda is rebuilt as Func<T, bool> so the resulting Queryable.Any call type-checks.

  • New TryConvertListExistsToQueryableAny helper alongside TryConvertCollectionContainsToQueryableContains
  • Detection branch gated to List<T> (other types like Array.Exists are out of scope)
  • Bails out when the receiver is a literal (new List<T> / new {...}) or the predicate is a non-lambda delegate
  • Flips four placeholder tests (Where_Join_Exists, _Inequality, _Constant, Where_Join_Not_Exists) tagged with // Issue #17762 from AssertTranslationFailed to AssertQuery
  • Populates SqlServer SQL baselines (EXISTS subquery + optimizer-simplified forms for constant-false predicates)
  • Cosmos overrides wrapped in AssertTranslationFailed per Cosmos's existing Issue #17246 pattern for navigation-collection Any translations

Fixes #17762

Rewrites List<T>.Exists(predicate) to AsQueryable().Any(predicate) in
QueryableMethodNormalizingExpressionVisitor, mirroring the existing
ICollection<T>.Contains conversion. The Predicate<T> lambda is rebuilt
as Func<T, bool> so the resulting Queryable.Any call type-checks.

Flips four placeholder tests (Where_Join_Exists, _Inequality, _Constant,
Where_Join_Not_Exists) from AssertTranslationFailed to AssertQuery, and
populates the SqlServer SQL baselines with the EXISTS subquery output.

Fixes dotnet#17762
@m-x-shokhzod m-x-shokhzod requested a review from a team as a code owner May 5, 2026 18:31
- Wrap Cosmos overrides for the 4 Where_Join_*Exists* tests in
  AssertTranslationFailed, matching the existing Cosmos pattern for
  navigation-collection Any-style queries (Issue dotnet#17246). The base test
  used to be wrapped in AssertTranslationFailed which covered Cosmos;
  after flipping the base to AssertQuery for the providers that can now
  translate, the failure-assertion has to live on Cosmos's override.

- Correct the expected SqlServer SQL for Where_Join_Exists_Constant and
  Where_Join_Not_Exists. EF's optimizer simplifies Any(o => false) and
  !Any(o => false) at translation time, so the EXISTS subquery does not
  appear in the emitted SQL. Pattern matches the existing Not_Any_false
  baseline in NorthwindAggregateOperatorsQuerySqlServerTest.
EF's optimizer recognizes that c.CustomerID == \"ALFKI\" && Exists(o => false)
short-circuits to false and eliminates the entire predicate, including the
customer-id filter. Actual emitted SQL is just \`WHERE 0 = 1\`, not
\`WHERE [c].[CustomerID] = N'ALFKI' AND 0 = 1\`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Query: Translate List.Exists

1 participant