So basically ran into performace issues due to new query plan generating every time. The problem being that values (itemIds) are translated as constants in sql's rpc rather than variables, thus generating separate plans for different combinations rather then one.
I found workaround replacing contains
statement with multiple OR
's using LinqKit
:
var filter = PredicateBuilder.New<Foo>();
foreach (var itemId in itemIds)
{
typeFilter = typeFilter.Or(foo => foo.ItemId == itemId);
}
var filteredItems = contex.Foos.Where(filter).ToList();
And it works. Now I'm trying to move it to extension method for reasons. Wrote extension but it failes to be translated by EF:
public static IQueryable<TSource> WhereContains<TSource, TInItem>(
this IQueryable<TSource> source,
IEnumerable<TInItem> inItems,
Expression<Func<TSource, TInItem>> selector
) where TInItem : IComparable
{
var containsFilter = PredicateBuilder.New<TSource>();
foreach (var item in inItems)
{
containsFilter = containsFilter.Or(x => selector.Invoke(x).Equals(item));
}
return source.Where(containsFilter);
}
Also I tried to work with following code, but it genrates same constants just in multiple OR
statements rather than on IN
. Probably Expression.Constant(item)
has to be changed some how but could not figure out how.
public static IQueryable<TSource> WhereContains<TSource, TInItem>(
this IQueryable<TSource> source,
List<TInItem> inItems,
Expression<Func<TSource, TInItem>> selector)
{
var itemParameter = Expression.Parameter(inItems.GetType());
var selectorParameter = selector.Parameters.Single();
var itemEqualSelectorBody = Expression.Equal(itemParameter, selector.Body);
var itemEqualSelectorLambda = Expression.Lambda<Func<TInItem, bool>>(itemEqualSelectorBody, itemParameter);
var containsFilter = inItems
.Select(item => Expression.Invoke(itemEqualSelectorLambda, Expression.Constant(item)))
.Aggregate<Expression>(Expression.OrElse);
return source.Where(Expression.Lambda<Func<TSource, bool>>(containsFilter, selectorParameter));
}
Can you point my mistakes? Over suggestions and solution will be appreciated.