Implement a LINQ Expression parameter - c#

I am using an interface I found, which has a method that takes a LINQ expression as a parameter.
How would I implement this method to use the LINQ Expression? I can see it being very useful, but dont how to write the code to use it!!
Its a repository interface.
signature is...
IQueryable<T> Get(Expression<Func<T, bool>> criteria);

Sounds like you are looking for something like this:
List<T> myList = new List<T>();
...
public IQueryable<int> Get(Expression<Func<int, bool>> criteria)
{
return myList.Where(criteria.Compile()).AsQueryable();
}
This passes your expression criteria to the linq-method Where. You can then call it like this:
foreach(var something in myClass.Get(o => o.someProperty == 10))
{
...
}
Of course, this is pretty stupid; it would be better to just implement IEnumerable<T>...

IQueryable<T> has an .Where() overload that takes an Expression<Func<T>> parameter. When assuming that this is a Linq2Sql or Linq2Entities repository, something like this should work
class MyRepository
{
ObjectContext context = // initialize somehow;
public IQueryable<int> Get(Expression<Func<int, bool>> predicate)
{
return context.SomeObject.Where(predicate);
}
}
If that's not the case, and you only have an enumerable, you can use AsQuerably() as the first step in the chain to convert it to IQuerably, giving you the option to use the expression based predicate:
public IQueryable<int> Get(Expression<Func<int, bool>> predicate)
{
return mySimpleList.AsQuerable().Where(predicate);
}

That is a predicate expression; something that indicates data to include.
So, to get a single record you could use:
int rowId = 123;
var row = foo.Get(x => x.Id == rowId).Single();
Or to get all data matching some condition you could use:
var allDeleted = foo.Get(x => x.IsDeleted).ToList();
Note that this should be composable, for more fun:
var today = from row in foo.Get(x => x.DateCreated > DateTime.Today)
orderby row.Name
select new {row.Id, row.Name};

Related

LINQ: How to filter two expressions with OR, while both have conditions to include filter?

I know that if (includeFilter) query = query.Where (...) gives the same result as query = query.Where (n => !includeFilter || <expression>).
But what if I have <expression1> and <expression2> and I want query.Where (n => <expression1> || <expression2>)? Except that there are includeFilter1 and includeFilter2 too.
Simply query.Where (n => (!includeFilter1 || <expression1>) || (!includeFilter2 || <expression2>)) won't work, because in case includeFilter1 is false, <expression2> will have no effect.
Update:
I just got to this solution:
```query.Where(n => !includeFilter1 || ).Union(query.Where(n => !includeFilter2 || ))```
I'm going to use it with IQueryable; is it OK? Is there a better solution?
Update 2:
I was wrong. What I needed was this:
var query1 = query.Where(n => !includeFilter1 || <expression1>)
var query2 = query.Where(n => !includeFilter2 || <expression2>)
if (includeFilter1 && includeFilter2)
query = query1.Union(query2);
else if (includeFilter1)
query = query1;
else if (includeFilter2)
query = query2;
I couldn't come up with a more elegant way.
In general .Union() is best reserved for cases where you can't represent the logic of the filter in a single query, or when the data is being drawn from different sources in each part of the query. Each .Union() call most likely results in a separate query execution, which means the query optimizer has little to no chance to produce a reasonable execution plan.
Using .Where(n => !includeFilter || <expression>) is also less that optimal on the face of it. The expression tree will close over the includeFilter variable and may not be optimized particularly well depending on the ORM you're using. Best to avoid that where possible.
There are several options for this kind of query composition. The simplest, which works fine for a couple of entries, is this:
if (includeFilter1)
{
if (includeFilter2)
query = query.Where(q => <expression1> || <expression2>);
else
query = query.Where(q => <expression1>);
}
else if (includeFilter2)
query = query.Where(q => <expression2>);
Not very elegant perhaps, but it works just fine and only takes a few lines of code to implement... if <expression1> and <expression2> are known at compile time and aren't parameters to the method.
What I think you're looking for is a more generic way to handle filter expression composition. LINQ has some rather interesting expression handling and while expressions can be scary at first, once you get the hang of them you can do some quite cool things.
For instance, here's an extension (and a supporting class) that will take two predicates on the same type and join them with an Or:
using System.Linq.Expressions
public static class ExpressionExtensions
{
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
{
// Useful for chained or conditional composition:
if (left is null)
return right;
if (right is null)
return left;
// Just in case:
if (ReferenceEquals(left, right))
return left;
// change right parameter references to match left
var rightBody = ReplaceVisitor.Replace(right.Body, right.Parameters[0], left.Parameters[0]);
// build 'or' expression
var body = Expression.OrElse(left.Body, rightBody);
// Create lambda (function) for predicate
var result = Expression.Lambda<Func<T, bool>>(body, left.Parameters[0]);
return result;
}
}
// Helper class, replaces expression instances
// Used to get the right parameters in composed expressions.
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression _from;
private readonly Expression _to;
private ReplaceVisitor(Expression from, Expression to)
{
_from = from;
_to = to;
}
public override Expression Visit(Expression e)
=> ReferenceEquals(e, _from) ? _to : base.Visit(e);
public static T Replace<T>(T expression, Expression from, Expression to)
where T : Expression
{
var visitor = new ReplaceVisitor(from, to);
return (T)visitor.Visit(expression);
}
}
(You can create a similar .And() extension using the AndAlso expression.)
Using that you can directly merge your filter expresions with an Or like so:
public IQueryable<T> ApplyFilters<T>(IQueryable<T> query,
bool useFilter1, Expression<Func<T, bool>> predicate1,
bool useFilter2, Expression<Func<T, bool>> predicate2
)
{
Expression<Func<T, bool>> predicate = null;
if (useFilter1)
predicate = predicate.Or(predicate1);
if (useFilter2)
predicate = predicate.Or(predicate2);
return predicate is null ? query : query.Where(predicate);
}
Or perhaps this:
public IQueryable<T> AnyOf<T>(IQueryable<T> query, params Expression<Func<T, bool>>[] filters)
{
Expression<Func<T, bool>> predicate = null;
foreach (var filter in filters)
predicate = predicate.Or(filter);
return predicate is null ? query : query.Where(predicate);
}
Try it out, see if it fits your use case.
I think you need
query.Where(n => (!includeFilter1 || <expression1>) &&
(!includeFilter2 || <expression2>))

How do I get 2 IQueryable<T> methods to implement a disjunction? [duplicate]

This question already has answers here:
Chaining / building LINQ query with an OR instead of AND
(2 answers)
Closed 6 years ago.
Appologies if this is a simple question; suppose I have an EF Query object with 2 methods:
public static IQueryable<Animal> FourLegged(this IQueryable<Animal> query)
{
return query.Where(r => r.NumberOfLegs == 4);
}
public static IQueryable<Animal> WithoutTail(this IQueryable<Animal> query)
{
return query.Where(r => !r.HasTail);
}
Now, in my service layer, to get animals that are four-legged AND without a tail, I can do:
_animalService.Query()
.FourLegged()
.WithoutTail();
That will result in an sql query like so:
select * from Animal where NumberOfLegs = 4 AND HasTail = 0
How do I use the 2 query methods with an OR instead? I want animals that are either 4 legged OR without a tail
select * from Animal where NumberOfLegs = 4 OR HasTail = 0
In Nhibernate I would have used a simple disjunction, but I can't find that in EF.
Thanks
Solution: I ended up using LinqKit predicates mentioned on this answer. It works quite well and I can reuse predicates too.
You can’t really do this when you already called query.Where(). The predicates there are already collected in the IQueryable and they are all combined by AND.
In order to get an OR you will have to make a single query.Where() call and pass a single expression that covers your various disjunctive predicates.
In your case, the combined predicate would look like this:
query.Where(r => (r.NumberOfLegs == 4) || (!r.HasTail))
To make that more dynamic, you essentially need to build a custom expression composition function that works like this:
Expression<Func<Animal, bool>> fourLegged = r => r.NumberOfLegs == 4;
Expression<Func<Animal, bool>> withoutTail = r => !r.HasTail;
query = query.Where(CombineDisjunctivePredicates(fourLegged, withoutTail));
So let’s write that CombineDisjunctivePredicates function:
public Expression<Func<T, bool>> CombineDisjunctivePredicates<T>(params Expression<Func<T, bool>>[] predicates)
{
Expression current = Expression.Constant(false);
ParameterExpression param = Expression.Parameter(typeof(T), "obj");
foreach (var predicate in predicates)
{
var visitor = new ReplaceExpressionVisitor(predicate.Parameters[0], param);
current = Expression.Or(current, visitor.Visit(predicate.Body));
}
return Expression.Lambda<Func<T, bool>>(current, param);
}
This basically takes a number of predicates and combines them by combining the expression bodies using the boolean OR. Since we are combining different expressions which may have different expression parameters, we also need to make sure to replace all expression parameter references in the expression bodies using a common parameter. We do this using a simple ReplaceExpressionVisitor, easily implemented like this:
public class ReplaceExpressionVisitor : ExpressionVisitor
{
private readonly Expression _original;
private readonly Expression _replacement;
public ReplaceExpressionVisitor(Expression original, Expression replacement)
{
_original = original;
_replacement = replacement;
}
public override Expression Visit(Expression node)
{
return node == _original ? _replacement : base.Visit(node);
}
}
And that’s all you need to combine the predicates. You just need to make sure to change your methods now so they don’t call query.Where themselves but return a Expression<Func<Animal, bool>> instead.

Cannot resolve method between Enumerable and Queryable candidates

I have this method in a class called Invoice:
public static Expression<Func<Invoice, bool>> IsAllocated()
{
return i => i.TotalAmountDue == i.GetAllocationsTotal();
}
I have a list like this:
IQueryable<Invoice> invoices
And I need to filter it like that (it's Linq to Entity):
var filteredInvoices = invoices.Where(i => Invoice.IsAllocated());
In this line I'm getting two errors:
Cannot resolve method ... candidates are .... one in Enumerable and the other on in Queryable.
And also:
Cannot convert expression type Expression<Func<Invoice,bool>> to
return type 'bool'
I've tried a lot of things I've found in SO with no luck. Can someone say me what is missing here or at least, which one of the two errors is at the root of the problem?
Your method returns an appropriate expression tree already - you just need to call it, not call it in a lambda expression:
var filteredInvoices = invoices.Where(Invoice.IsAllocated());
Expression are representation and not delegate by themselves. You should create a delegate out of it first
static Expression<Func<Invoice, bool>> IsAllocatedExpr()
{
return i => i.TotalAmountDue == i.GetAllocationsTotal();
}
public static Func<Invoice, bool> IsAllocated = IsAllocatedExpr().Compile();
and then
var filteredInvoices = invoices.Where(i => Invoice.IsAllocated(i));

Building a custom predicate to act as a filter using a foreach loop

I need to filter a list of documents by passing them to a custom filter that I'm struggling to build dynamically using a foreach loop :
var mainPredicate = PredicateBuilder.True<Document>();
// mainPredicate is combined to other filters successfully here ...
var innerPredicate = PredicateBuilder.False<Document>();
foreach (var period in periods)
{
var p = period;
Expression<Func<Document, bool>> inPeriod =
d => d.Date >= p.DateFrom && d.Date <= p.DateTo;
innerPredicate = innerPredicate.Or(d => inPeriod.Invoke(d));
}
mainPredicate = mainPredicate.And(innerPredicate);
This last line :
documents = this.ObjectSet.AsExpandable().Where(mainPredicate).ToList();
Throws this exception :
The parameter 'd' was not bound in the specified LINQ to Entities
query expression.
Anyone knows why I'm getting this exception ? I don't understand where the 'd' parameter I am passing to the InPeriod method gets lost. I don't know what is missing for this to work. My code is the same as many other examples that work perfectly. Any additionnal theoric theoric information about invoking expressions and how it works behind the scenes are welcome.
I don't understand why you do this:
innerPredicate = innerPredicate.Or(d => inPeriod.Invoke(d));
When you could just avoid the Invoke completely, like this:
innerPredicate = innerPredicate.Or(inPeriod);
This should work perfectly fine.
BTW, I have a feeling there's a bug with LINQKit here (unless there's some documentation that suggests that it doesn't support this scenario).
When I tried this similar code:
Expression<Func<int, bool>> first = p1 => p1 > 4;
Expression<Func<int, bool>> second = p2 => p2 < 2;
// Expand is similar to AsExpandable, except it works on
// expressions, not queryables.
var composite = first.Or(d => second.Invoke(d))
.Expand();
...LINQKit generated the following composite expression:
p1 => ((p1 > 4) OrElse (d < 2)) // what on earth is d?
... which indeed has the unbound parameter d (NodeType = Parameter, Name = 'd').
Dodging the Invoke with first.Or(second).Expand() generates the perfectly sensible:
p1 => ((p1 > 4) OrElse (p1 < 2)) // much better now...
Finally, I have found a way to avoid combining multiple predicates to the main expression tree.
Given that each predicate represents a different filter and I want the final, combined filter to be a series of must-be-respected conditions, we can say that each of the predicates has to return true for the final predicate to return true.
For that to work, the predicates has to be combined with AND. So, the resulting SQL query must look like this :
predicate1 AND predicate2 AND predicate3 ...
A better way to combine these predicates with AND is to chain Where query operators to the final query, like this :
var documents = this.ObjectSet.AsExpandable()
.Where(mainPredicate)
.Where(otherPredicate)
.Where(yetAnotherPredicate)
.ToList();
The resulting SQL query will combine each of these predicates with AND. That is just what I wanted to do.
It is easier than hacking out an expression tree by myself.
I use these extension methods:
public static class Extensions
{
public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> source, Expression<Func<T, bool>> predicate)
{
InvocationExpression invokedExpression = Expression.Invoke(predicate, source.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(source.Body, invokedExpression), source.Parameters);
}
public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> source, Expression<Func<T, bool>> predicate)
{
InvocationExpression invokedExpression = Expression.Invoke(predicate, source.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(source.Body, invokedExpression), source.Parameters);
}
}

Invoke a C# inner Expression with a member property of a parameter to an outer expression

I am using the Albaharis PredicateBuilder as found here http://www.albahari.com/nutshell/predicatebuilder.aspx to filter results in a Linq-to-SQL application. This has been working great.
What I am trying to do now, is reuse the existing filtering predicate expression to filter an object that has the existing filtered object as a property.
For example, I have 2 classes, Order and Customer. I already have a method that returns a Expression<Func<Customer, bool>>, which is built using the above mentioned predicate builder. I now want to reuse this in my Order filtering method, which will return a Expression<Func<Customer, bool>> by somehow passing the Order.Customer property (expression?) into my Customer filter method.
I have something like this (far from complete, but I hope you get the idea):
public class CustomerSearchCriteria
{
public Expression<Func<Customer, bool>> FilterPredicate()
{
// Start with predicate to include everything
var result = PredicateBuilder.True<Customer>();
// Build predicate from criteria
if (!String.IsNullOrEmpty(this.Name))
{
result = result.And(c => SqlMethods.Like(c.Name, this.Name));
}
// etc. etc. etc
}
public class OrderSearchCriteria
{
public Expression<Func<Order, bool>> FilterPredicate()
{
// Start with predicate to include everything
var result = PredicateBuilder.True<Order>();
// Build predicate from criteria
if (!String.IsNullOrEmpty(this.Reference))
{
result = result.And(o => SqlMethods.Like(o.Reference, this.Reference));
}
// etc. etc. etc
// This is where I would like to do something like:
// result = result.And(o => o.Customer "matches" this.CustomerCriteria.FilterPredicate()
}
Can any Linq expression guru help me?
Thanks in advance.
If you use the Albaharis' LinqKit, you should be able to do something like this:
var customerFilter = this.CustomerCriteria.FilterPredicate();
// create an expression that shows us invoking the filter on o.Customer
Expression<Func<Order, bool>> customerOrderFilter =
o => customerFilter.Invoke(o.Customer);
// "Expand" the expression: this creates a new expression tree
// where the "Invoke" is replaced by the actual predicate.
result = result.And(customerOrderFilter.Expand())

Categories