The package LINQKit, a solution for making queries dynamically extendable at runtime, currently sits at half a million downloads for EF Core alone, with much more for traditional EF.
The old uservoice forums had an issue with 114 upvotes, which puts it on the frontpage of that now shuttered forum.
Dynamic queries like PredicateBuilder currently only exist as an external solution (as part of LINQKit). It would be preferable to have this functionality be part of EF Core.
There are a dozen advantages for including this upstream:
Note from triage: we should investigate what makes sense in this space. For example, that might be making sure EF Core works well with LINQKit and making it easier for the two to keep working across releases.
We mostly use LINQKit for the reuse of .Where(....) for special business logic that is reused in allot of places that might need to be changed in the future (or just have a simple\easier name for it),
and .Select(.....) for selecting some common models that are reused in a bunch of places
if only that feature would make it into EF Core itself i would be very happy
also i have noticed that EF Core is not able to optimize the sql generated when a select\where (expression) has been invoked using LINQKit (we have a bunch of heavy queries so i open sql profiler allot and look at sql being generated)
And now i'm blocked from upgrading to EF Core 3.0 #https://github.com/scottksmith95/LINQKit/issues/95
Official support for the feature i meantioned above would remove my dependency on LINQKit (I really like the library but built in support would be better of course :smile: )
well I think PredicateBuilder is something that people want. But most functionality of that is already in EFCore. you can AND where parts together when writing code like that:
var query = ...
foreach (...)
{
query = query.Where(...)
}
However OR'ing is completly missing. Probably because it would need a good api design to not confuse users.
WhereOr Expression can be simulated like that:
internal class RangeMemberExpressionModifier : ExpressionVisitor
{
private readonly ParameterExpression _parameterExpression;
public RangeMemberExpressionModifier(ParameterExpression parameterExpression)
{
_parameterExpression = parameterExpression;
}
public Expression Modify(Expression expression)
{
return Visit(expression);
}
protected override Expression VisitParameter(ParameterExpression node)
{
return _parameterExpression;
}
}
public class QueryPartOrBuilder<TSource>
{
internal readonly List<Expression<Func<TSource, bool>>> PredicateLists = new List<Expression<Func<TSource, bool>>>();
public void Add(Expression<Func<TSource, bool>> predicate)
{
PredicateLists.Add(predicate);
}
}
public static IQueryable<TSource> WhereOr<TSource>(this IQueryable<TSource> query, QueryPartOrBuilder<TSource> orBuilder)
{
var predicates = orBuilder.PredicateLists;
if (predicates.Count == 0)
{
return query;
}
if (predicates.Count == 1)
{
return query.Where(predicates[0]);
}
var parameter = predicates.FirstOrDefault()?.Parameters.FirstOrDefault();
if (parameter == null)
{
throw new ArgumentException("invalid parameter name");
}
var modifier = new RangeMemberExpressionModifier(parameter);
var aggregatedExpressions = predicates.Aggregate<Expression>((first, second) =>
{
Expression me1;
switch (first)
{
case LambdaExpression le:
me1 = modifier.Modify(le.Body as BinaryExpression);
break;
case BinaryExpression be:
me1 = be;
break;
default:
throw new ArgumentException("arguments should not be null");
}
var body2 = (second as LambdaExpression)?.Body;
if (body2 == null)
{
throw new ArgumentException("arguments should not be null");
}
var me2 = modifier.Modify(body2 as BinaryExpression);
return Expression.OrElse(me1, me2);
});
return query.Where(Expression.Lambda<Func<TSource, bool>>(aggregatedExpressions, parameter));
}
Schmitch's code works perfectly! It would it be nice to have a similar WhereOr function in EF Core.
Most helpful comment
We mostly use LINQKit for the reuse of
.Where(....)for special business logic that is reused in allot of places that might need to be changed in the future (or just have a simple\easier name for it),and
.Select(.....)for selecting some common models that are reused in a bunch of placesif only that feature would make it into EF Core itself i would be very happy
also i have noticed that EF Core is not able to optimize the sql generated when a select\where (expression) has been invoked using LINQKit (we have a bunch of heavy queries so i open sql profiler allot and look at sql being generated)