-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Description
Note: this issue tracks only fixing Contains. Other non-lambda operators (Skip, Take, ElementAt...) are tracked by #32312, to have two quirks for Contains and non-Contains.
When running test Nested_contains_with_Lists_and_no_inferred_type_mapping (introduced in #32214), which has the following code:
var ints = new List<int> { 1, 2, 3 };
var strings = new List<string> { "one", "two", "three" };
return AssertQuery(
async,
ss => ss.Set<PrimitiveCollectionsEntity>().Where(e => strings.Contains(ints.Contains(e.Int) ? "one" : "two")));
... the query tree going into nav expansion is:
DbSet<PrimitiveCollectionsEntity>()
.Where(e => __strings_0
.AsQueryable()
.Contains(__ints_1
.AsQueryable()
.Contains(e.Int) ? "one" : "two"))
... whereas the tree coming out is:
DbSet<PrimitiveCollectionsEntity>()
.Where(p => __strings_0
.Contains(__ints_1
.AsQueryable()
.Contains(p.Int) ? "one" : "two"))
Note that the outer AsQueryable (over __strings_0
) is gone, while the inner one (over __ints_1
) remains.
What's happening here is this... NavigationExpandingEV works recursively on lambda arguments of operators; ProcessWhere calls into ProcessLambdaExpression, which calls into ExpandNavigationsForSource which visits the the Where predicate. This causes the Where lambda to be fully processed by the visitor, and the AsQueryable wrapping __strings_0
is removed.
However, ProcessContains does not similarly recurse into the item argument of Contains; so the AsQueryable there isn't removed.
Note that there may be other important functionality of nav expansion which is not performed here; and there are other operator aside from Contains which likely don't visit their non-lambda arguments. So there are probably other bugs hiding in here.
When this is fixed, we can remove the unwrapping of AsQueryable() from the fallback Contains translation (see #32218).