building OR expression from List of strings [duplicate] - c#

This question already has answers here:
Combining two expressions (Expression<Func<T, bool>>)
(10 answers)
Closed 9 months ago.
In the code below :
Expression<Func<WorkflowTask, bool>> filterBefore = wt => true;
filterBefore = filterBefore.And(wt => wt.code == "XK");
List<string> sourceLanguages = new List<string>() { "FR", "DE", "NL" };
//HOW TO BUILD OR CONDITIONS DYNAMICALLY BASED ON SOURCE LANGUAGES LIST ?
filterBefore = filterBefore.And(wt => wt.SourceLanguages.Contains("FR") || wt.WorkflowTaskContextualInfo.SourceLanguages.Contains("DE"));
I don't know how to build dynamically the OR condition on the SourceLanguages List. That list could contain any number of values (I've hardcoded it here for the sake of example).
wt.WorkflowTaskContextualInfo.SourceLanguages is a string with comma-separated values ("FR, EN" for instance)
The And expression is defined as below :
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
}

LINQKit's PredicateBuilder is designed specifically to address this kind of need. But if you feel that's too much overhead, you can craft your own Expression tree with a few simple utilities, as I've described in this answer
First, a general-purpose Expression Replacer:
public class ExpressionReplacer : ExpressionVisitor
{
private readonly Func<Expression, Expression> replacer;
public ExpressionReplacer(Func<Expression, Expression> replacer)
{
this.replacer = replacer;
}
public override Expression Visit(Expression node)
{
return base.Visit(replacer(node));
}
}
Next, a simple utility method to replace one parameter's usage with another parameter in a given expression:
public static T ReplaceParameter<T>(T expr, ParameterExpression toReplace, ParameterExpression replacement)
where T : Expression
{
var replacer = new ExpressionReplacer(e => e == toReplace ? replacement : e);
return (T)replacer.Visit(expr);
}
This is necessary because the lambda parameters in two different expressions are actually different parameters, even when they have the same name. For example, if you want to end up with q => q.first.Contains(first) || q.last.Contains(last), then the q in q.last.Contains(last) must be the exact same q that's provided at the beginning of the lambda expression.
Next we need a general-purpose Join method that's capable of joining Func<T, TReturn>-style Lambda Expressions together with a given Binary Expression generator.
public static Expression<Func<T, TReturn>> Join<T, TReturn>(Func<Expression, Expression, BinaryExpression> joiner, IReadOnlyCollection<Expression<Func<T, TReturn>>> expressions)
{
if (!expressions.Any())
{
throw new ArgumentException("No expressions were provided");
}
var firstExpression = expressions.First();
var otherExpressions = expressions.Skip(1);
var firstParameter = firstExpression.Parameters.Single();
var otherExpressionsWithParameterReplaced = otherExpressions.Select(e => ReplaceParameter(e.Body, e.Parameters.Single(), firstParameter));
var bodies = new[] { firstExpression.Body }.Concat(otherExpressionsWithParameterReplaced);
var joinedBodies = bodies.Aggregate(joiner);
return Expression.Lambda<Func<T, TReturn>>(joinedBodies, firstParameter);
}
Now, applying that to your example:
Expression<Func<WorkflowTask, bool>> codeCriteria = wt => wt.code == "XK";
var langCriteria = new List<string>() { "FR", "DE", "NL" }
.Select(lang => (Expression<Func<WorkflowTask, bool>>)(wt => wt.SourceLanguages.Contains(lang)))
.ToList();
var filter = Join(Expression.And, new[] { codeCriteria, Join(Expression.Or, langCriteria)});
filter will now have the equivalent of wt => wt.code == "XK" && (wt.SourceLanguages.Contains("FR") || wt.SourceLanguages.Contains("DE") || wt.SourceLanguages.Contains("NL"))

I would put the required languages in an array or list.
var required = new string[]{ "FR", "DE" };
Then you can query with
wt => required.Any(r => wt.SourceLanguages.Contains(r))
or, the other way round
wt => wt.SourceLanguages.Any(sl => required.Contains(sl))

I did not feel like importing a whole library, and the sample given seemed a bit of a stretch so I think i found an easier solution using BinaryExpression Update(Expression left, LambdaExpression? conversion, Expression right).
The samples below accepts a list of string, and constructs a chain of OR expressions. Each OR expressions calls a entity framework's LIKE method. In the end the whole ordeal gets translated nicely to SQL - so if you're on the job of making dynamic filters like i did - this should help you out.
private static Expression<Func<TMeta, bool>> GetMetaKeyFilterPredicateExpression<TMeta>(List<string> metaKeyNames)
where TMeta : IMetaKeyValuePair
{
var parameter = Expression.Parameter(typeof(TMeta));
var property = Expression.Property(Expression.Convert(parameter, typeof(IMetaKeyValuePair)),
propertyName: nameof(IMetaKeyValuePair.MetaKey));
Expression body = null!;
BinaryExpression? predicateExpression = null;
foreach (var metaKeyName in metaKeyNames)
{
var likeExpression = Expression.Call(typeof(DbFunctionsExtensions),
nameof(DbFunctionsExtensions.Like),
null,
Expression.Constant(EF.Functions),
property,
Expression.Constant(metaKeyName)
);
predicateExpression =
predicateExpression == null
? Expression.Or(likeExpression, Expression.Constant(false))
: predicateExpression.Update(predicateExpression, null, likeExpression);
}
body = (Expression?)predicateExpression ?? Expression.Constant(true);
var expr = Expression.Lambda<Func<TMeta, bool>>(body: body, parameter);
return expr;
}
var expr = GetMetaKeyFilterPredicateExpression<TMeta>(metaKeyNames);
qMetaKeyValuePairs = qMetaKeyValuePairs.Where(expr);

Related

How to combine expressions Expression<Func<T1, T2, bool>> to a single Expression<Func<T2, bool>>

I have a list of conditions composed of two Funcs:
public Func<TConfiguration, string> ConfigurationField { get;}
public Func<TNumbering, string> NumberingField { get; }
For each condition, expression would look like this:
Expression<Func<TNumbering, TConfiguration, bool>> (n, c) => criteria.ConfigurationField(c) != criteria.NumberingField(n)
I need to chain the list of these expressions with OrElse.
I tried doing something like:
BinaryExpression expression = null;
foreach (var criteria in SelectionCriteria)
{
Expression<Func<TNumbering, TConfiguration, bool>> exp = (n, c) => criteria.ConfigurationField(c) != criteria.NumberingField(n);
expression = expression == null ? exp : Expression.OrElse(expression, exp);
}
if (expression == null) return Result.Failure("Expression not defined"));
var lambda = Expression.Lambda<Func<TConfiguration, bool>>(expression);
numberingsToRemove = numberings.Where(_ => configurations.All(lambda));
However, compiler doesn't like it, says there is no implicit conversion between Expression.Lambda<Func<TConfiguration, bool>> and Binary expression.
If I use
expression = expression == null ? Expression.OrElse(exp, exp) : Expression.OrElse(expression, exp);
I get
The binary operator OrElse is not defined for the types 'System.Func<TNumbering,TConfiguration,System.Boolean> and 'System.Func<TNumbering,TConfiguration,System.Boolean>.
I am new to building expressions, can somebody point me in the right direction how to do this?
Your Expression<Func<TNumbering, TConfiguration, bool>> is a generic type whose open generic type is Expression<TDelegate>, where TDelegate is some delegate type; in this case Func<TNumbering, TConfiguration, bool>.
Expression<TDelegate> inherits from LambdaExpression, which represents a C# (or VB.NET) lambda expression.
Just like you couldn't write the following code:
var result =
(n, c) => criteria.ConfigurationField(c) != criteria.NumberingField(n) ||
(n1, c1) => criteria.ConfigurationField(c1) != criteria.NumberingField(n1);
trying to combine two LambdaExpressions with OrElse would throw an exception at runtime.
Your code isn't even compiling, because expression is typed as BinaryExpression, meaning an expression corresponding to this:
criteria.ConfigurationField(c) != criteria.NumberingField(n) ||
criteria.ConfigurationField(c1) != criteria.NumberingField(n1)
into which you're trying to put a full Expression<TDelegate>, which includes (for example) the parameter list.
Every LambdaExpression has a Body property, which extracts from an expression corresponding to this:
(n, c) => criteria.ConfigurationField(c) != criteria.NumberingField(n)
the body of the LambdaExpression, or an expression corresponding to this:
criteria.ConfigurationField(c) != criteria.NumberingField(n)
which, in theory, you could then combine into a BinaryExpression corresponding to this:
criteria.ConfigurationField(c) != criteria.NumberingField(n) ||
criteria.ConfigurationField(c1) != criteria.NumberingField(n1)
But this wouldn't work either, because each iteration introduces multiple new parameters, all of which you'd have to pass in to the final lambda.
It's possible to work around this problem, but I would suggest first and foremost you map each element in SelectionCriteria to an expression corresponding to the criteria evaluation, using the factory methods at System.Linq.Expressions.Expression. You could then combine those expressions into a BinaryExpression which you could then wrap up in a LambdaExpression or even an Expression.
It might look something like this (making some assumptions):
class Criteria<TConfiguration, TNumbering> {
public Func<TConfiguration, string> ConfigurationField { get;}
public Func<TNumbering, string> NumberingField { get; }
}
// using static System.Linq.Expressions.Expression;
var SelectionCritera = new List<Criteria>();
/*
* populate list here
*/
var configParam = Parameter(typeof(TConfiguration));
var numberingParam = Parameter(typeof(TNumbering));
var expressions =
SelectionCriteria.Select(criteria => {
var criteriaExpr = Constant(criteria);
return NotEqual( // !=
Invoke( // ( ... )
PropertyOrField( // .ConfigurationField
criteriaExpr, // criteria
"ConfigurationField"
),
configParam // c
),
Invoke( // ( ... )
PropertyOrField( // .NumberingField
criteriaExpr, // criteria
"NumberingField"
),
numberingParam // n
)
);
})
.ToList();
if (!expressions.Any) { return Result.Failure("Expression not defined")); }
// Combine all the subexpressions using ||
var body = expressions.Aggregate((prev, next) => OrElse(prev, next));
// Create a LambdaExpression
var lmbd = Lambda<Func<TConfiguration, TNumbering, bool>>(body, configParam, numberingParam);
// Create a .NET method from the LambdaExpression
var mthd = lmbd.Compile();
// Apply the method to each config/numbering pair
var result = (
from config in configs
from numbering in numbering
select (config, numbering)
).All(x => mthd(config, numbering));

How do I create a lambda expression using return value from another lambda expression? [duplicate]

This question already has an answer here:
Convert Linq expression "obj => obj.Prop" into "parent => parent.obj.Prop"
(1 answer)
Closed 4 years ago.
Neither the question nor the answer is the same as the question "Convert Linq expression “obj => obj.Prop” into “parent => parent.obj.Prop”". The only duplicate I've found on here lately is the number of duplicate mods with control issues.
I'm attempting to make a extension method for Entity Framework that will add a "Contains" call on a field if the given value is not null or whitespace. It's out of pure laziness of not wanting all the if statement checks for null or whitespace.
I want to be able to use it like this:
var qry = MyDb.Redacteds.OrderBy(a=>a.RedactedDate);
qry = qry.WhereContains(a => a.RedactedName, txtRedactedName.Text);
I've come up with this, but obviously the Invoke causes an issue with EF. What's the trick to using the result of a lambda when building an expression?
// create
// ent => exp(ent).Contains(s)
public static IQueryable<T> WhereContains<T>(this IQueryable<T> qry, Expression<Func<T, string>> exp, string s)
{
if (!string.IsNullOrWhiteSpace(s))
{
s = s.Trim();
var param = Expression.Parameter(typeof(T), "ent");;
var call = Expression.Invoke(exp, param); // <-= HERE
var body = Expression.Call(call, typeof(string).GetMethod("Contains", new[] { typeof(string) }), Expression.Constant(s));
var lambda = Expression.Lambda<Func<T, bool>>(body, param);
qry = qry.Where(lambda);
}
return qry;
}
If it was simply a delegate instead of a lambda, the return could simple be:
ent => exp(ent).Contains(s)
That's what I'm looking to do.
You want to grab the parameter off the lambda and use the body as the expression. You aren't using it as a lambda at all - you are picking the expression tree and parameters out of the lambda.
// create
// ent => exp(ent).Contains(s)
public static IQueryable<T> WhereContains<T>(this IQueryable<T> qry, Expression<Func<T, string>> exp, string s)
{
if (!string.IsNullOrWhiteSpace(s))
{
s = s.Trim();
//HERE GRAB THE PARAMETER
var param = exp.Parameters[0];
//HERE JUST USE EXP.BODY
var body = Expression.Call(exp.Body, typeof(string).GetMethod("Contains", new[] { typeof(string) }), Expression.Constant(s));
var lambda = Expression.Lambda<Func<T, bool>>(body, param);
qry = qry.Where(lambda);
}
return qry;
}

Search a term in multiple columns

I'd like to create an extension to search terms in multiple columns.
Terms are separated with space, each term must appears to at least one given column.
Here what I've done so far:
public static IQueryable<TSource> SearchIn<TSource>(this IQueryable<TSource> query,
string searchText,
Expression<Func<TSource, string>> expression,
params Expression<Func<TSource, string>>[] expressions)
{
if (string.IsNullOrWhiteSpace(searchText))
{
return query;
}
// Concat expressions
expressions = new[] { expression }.Concat(expressions).ToArray();
// Format search text
var formattedSearchText = searchText.FormatForSearch();
var searchParts = formattedSearchText.Replace('\'', ' ').Split(' ');
// Initialize expression
var pe = Expression.Parameter(typeof(TSource), "entity");
var predicateBody = default(Expression);
// Search in each expressions, put OR in between
foreach (var expr in expressions)
{
var exprBody = default(Expression);
// Search for each words, put AND in between
foreach (var searchPart in searchParts)
{
// Create property or field expression
var left = Expression.PropertyOrField(pe, ((MemberExpression)expr.Body).Member.Name);
// Create the constant expression with current word
var search = Expression.Constant(searchPart, typeof(string));
// Create the contains function
var contains = Expression.Call(left, typeof(string).GetMethod(nameof(string.Contains), new Type[] { typeof(string) }), search);
// Check if there already a predicate body
if (exprBody == null)
{
exprBody = contains;
}
else
{
exprBody = Expression.And(exprBody, contains);
}
}
if (predicateBody == null)
{
predicateBody = exprBody;
}
else
{
predicateBody = Expression.OrElse(predicateBody, exprBody);
}
}
// Build the where method expression
var whereCallExpression = Expression.Call(
typeof(Queryable),
nameof(Queryable.Where),
new Type[] { query.ElementType },
query.Expression,
Expression.Lambda<Func<TSource, bool>>(predicateBody, new ParameterExpression[] { pe }));
// Apply the condition to the query and return it
return query.Provider.CreateQuery<TSource>(whereCallExpression);
}
It works well as long as given expressions are simple:
// It works well
query.SearchIn("foo", x => x.Column1, x => x.Column2);
But it does not work when trying to navigate through navigation properties:
// Not working
query.SearchIn("foo", x => x.Nav1.Column1);
It gives me an exception.
'Column1' is not a member of type 'Nav1'.
I understand the problem but I can't find the solution to pass through Nav1.
I need help with this one.
Instead of parsing lambda expression body just call it with given parameter:
var left = Expression.Invoke(expr, pe);
However it works only in EF Core.
In EF6 you would need to get property or field of each nested member like this:
var left = expr.Body.ToString()
.Split('.')
.Skip(1) //skip the original parameter name
.Aggregate((Expression)pe, (a, c) => Expression.PropertyOrField(a, c));
It will work only for simple lambdas like:
x => x.Prop1.Nav1
If that's not enough you would need some more advanced parsing algorithm with ExpressionVisitor for example.

How to use Expression(Of TDelegate).Update Method

I have built a repository using Lambda expressions to filter my entity collections. As a parameter to the method I'm sending Expression<Func<Case, bool>> exp. But inside the method I would like to update that same expression with some global filters. I can see that the expression object itself got an Update method, but I can't figure out how it is implemented (and cannot find anything while searching the net).
exp.Update(exp.Body, ???);
Could anyone give an example??
EDIT: Definition of the method: http://msdn.microsoft.com/en-us/library/ee378255.aspx
EDIT2: This is my code (where I try to use .And):
Expression<Func<Case, bool>> newExp = c => c.CaseStatusId != (int)CaseStatus.Finished
var binExp = Expression.And(exp.Body, newExp.Body);
ParameterExpression paramExp = Expression.Parameter(typeof(Expression<Func<Case, bool>>), "c");
return repository.Where(Expression.Lambda<Expression<Func<Case, bool>>>(binExp,
new[] { paramExp }).Compile()).ToArray();
It fails with the following ArgumentException: Lambda type parameter must be derived from System.Delegate
I don't think the Update method can help you here. It only creates a new lambda, but does not update the original parameters with the new one, you have to do it manually.
I'd recommend having a visitor that replaces the parameter, then you can And the expressions together.
In total you would get something like:
private Case[] getItems(Expression<Func<Case, bool>> exp)
{
return repository.Where(AddGlobalFilters(exp).Compile()).ToArray();
}
private Expression<Func<Case, bool>> AddGlobalFilters(Expression<Func<Case, bool>> exp)
{
// get the global filter
Expression<Func<Case, bool>> newExp = c => c.CaseStatusId != (int)CaseStatus.Finished;
// get the visitor
var visitor = new ParameterUpdateVisitor(newExp.Parameters.First(), exp.Parameters.First());
// replace the parameter in the expression just created
newExp = visitor.Visit(newExp) as Expression<Func<Case, bool>>;
// now you can and together the two expressions
var binExp = Expression.And(exp.Body, newExp.Body);
// and return a new lambda, that will do what you want. NOTE that the binExp has reference only to te newExp.Parameters[0] (there is only 1) parameter, and no other
return Expression.Lambda<Func<Case, bool>>(binExp, newExp.Parameters);
}
/// <summary>
/// updates the parameter in the expression
/// </summary>
class ParameterUpdateVisitor : ExpressionVisitor
{
private ParameterExpression _oldParameter;
private ParameterExpression _newParameter;
public ParameterUpdateVisitor(ParameterExpression oldParameter, ParameterExpression newParameter)
{
_oldParameter = oldParameter;
_newParameter = newParameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (object.ReferenceEquals(node, _oldParameter))
return _newParameter;
return base.VisitParameter(node);
}
}
System.Linq.Expressions.Expression.And(exp.Body, newExpression.Body);
exapmle:
Expression<Func<int, bool>> f = p => true;
var a = Expression.And(f.Body, f.Body);
ParameterExpression pParam = Expression.Parameter(typeof(int), "p");
var b = (new int[] { 1, 2, 3 }).Where(Expression.Lambda<Func<int, bool>>(a,
new ParameterExpression[] { pParam }).Compile());

Is there an easy way to append lambdas and reuse the lambda name in order to create my Linq where condition?

I have a user control which takes a Func which it then gives to the Linq "Where" extension method of a IQueryable. The idea is that from the calling code, I can pass in the desired search function.
I'd like to build this search function dynamically as such:
Func<Order, bool> func == a => true;
if (txtName.Text.Length > 0) {
//add it to the function
func = a => func(a) && a.Name.StartsWith(txtName.Text);
}
if (txtType.Text.Length > 0) {
//add it to the function
func = a => func(a) && a.Type == txtType.Text;
}
..... etc .....
The problem with this approach is that since I'm reusing the name "func" it creates a recursive function.
Is there an easy way to build out the expression tree like this to make a dynamic where clause (in the absence of having the IQueryable up front and repeatedly calling "Where")?
Just save the current lambda in a temporary variable to prevent recursion.
var tempFunc = func;
func = a => tempFunc(a) && ...
If you want to do an "and" combination, the preferred option is to use multiple "where" clauses:
IQueryable<Order> query = ...
if (!string.IsNullOrEmpty(txtName.Text.Length)) {
//add it to the function
query = query.Where(a => a.Name.StartsWith(txtName.Text));
}
if (!string.IsNullOrEmpty(txtType.Text.Length)) {
//add it to the function
query = query.Where(a => a.Type == txtType.Text);
}
You can do more complex things with expression building (AndAlso, Invoke, etc), but this is not necessary for an "and" combination.
If you really need to combine expressions, then the approach depends on the implementation. LINQ-to-SQL and LINQ-to-Objects support Expression.Invoke, allowing:
static Expression<Func<T, bool>> OrElse<T>(
this Expression<Func<T, bool>> lhs,
Expression<Func<T, bool>> rhs)
{
var row = Expression.Parameter(typeof(T), "row");
var body = Expression.OrElse(
Expression.Invoke(lhs, row),
Expression.Invoke(rhs, row));
return Expression.Lambda<Func<T, bool>>(body, row);
}
static Expression<Func<T, bool>> AndAlso<T>(
this Expression<Func<T, bool>> lhs,
Expression<Func<T, bool>> rhs)
{
var row = Expression.Parameter(typeof(T), "row");
var body = Expression.AndAlso(
Expression.Invoke(lhs, row),
Expression.Invoke(rhs, row));
return Expression.Lambda<Func<T, bool>>(body, row);
}
However, for Entity Framework you will usually need to rip the Expression apart and rebuild it, which is not easy. Hence why it is often preferable to use Queryable.Where (for "and") and Queryable.Concat (for "or").
I am right in the middle of doing exactly this... I am using Expressions because Func is compiled code where as Expression<Func<YourObect, boo>> can be converted C# or TSql or what ever... I just have seen several people recommend using expression instead of just func.
On you search page you would implement the code like this:
SearchCritera<Customer> crit = new SearchCriteria<Customer>();
if (txtName.Text.Length > 0) {
//add it to the function
crit.Add(a.Name.StartsWith(txtName.Text));
}
if (txtType.Text.Length > 0) {
//add it to the function
crit.Add(a.Type == txtType.Text));
}
The SearchCriteria object look something like this...
public class SearchCritera<TEntity>
{
private List<Expression<Func<TEntity, bool>>> _Criteria = new List<Expression<Func<TEntity, bool>>>();
public void Add(Expression<Func<TEntity, bool>> predicate)
{
_Criteria.Add(predicate);
}
// This is where your list of Expression get built into a single Expression
// to use in your Where clause
public Expression<Func<TEntity, bool>> BuildWhereExpression()
{
Expression<Func<TEntity, bool>> result = default(Expression<Func<TEntity, bool>>);
ParameterExpression parameter = Expression.Parameter(typeof(TEntity), "entity");
Expression previous = _Criteria[0];
for (int i = 1; i < _Criteria.Count; i++)
{
previous = Expression.And(previous, _Criteria[i]);
}
result = Expression.Lambda<Func<TEntity, bool>>(previous, parameter);
return result;
}
}
Then from your Where clause you could do this...
public List<Customer> FindAllCustomers(SearchCriteria criteria)
{
return LinqToSqlDataContext.Customers.Where(SearchCriteria.BuildWhereExpression()).ToList();
}
This is the first time I have coded this out and you might need to make some changes for your purposes, I know it compliles but when I acutally go to do it I will unit test it, but it is the idea I have been tossing around in my head...
If you're going to be using this in LinqToSQL or any other dynamic expression tree parser, you're going to want to use PredicateBuilder!!!
Otherwise:
This extension method will prevent the recursion:
public static Func<T, bool> And<T>(this Func<T, bool> f1, Func<T, bool> f2)
{
return a => f1(a) && f2(a);
}
public static Func<T, bool> Or<T>(this Func<T, bool> f1, Func<T, bool> f2)
{
return a => f1(a) || f2(a);
}
Use it like so:
Func<Order, bool> func == a => true;
if (txtName.Text.Length > 0) {
//add it to the function
func.And(a => a.Name.StartsWith(txtName.Text));
}
if (txtType.Text.Length > 0) {
//add it to the function
func.And(a => a.Type == txtType.Text);
}
Dictionary<Func<bool>, Expression<Func<Order, bool>>> filters =
new Dictionary<Func<bool>, Expression<Func<Order, bool>>>();
// add a name filter
filters.Add(
() => txtName.Text.Length > 0,
a => a.Name.StartsWith(txtName.Text)
);
// add a type filter
filters.Add(
() => txtType.Text.Length > 0,
a => a.Type == txtType.Text
);
...
var query = dc.Orders.AsQueryable();
foreach( var filter in filters
.Where(kvp => kvp.Key())
.Select(kvp => kvp.Value) )
{
var inScopeFilter = filter;
query = query.Where(inScopeFilter);
}

Categories