Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linq-to-SQL combining two Expression<Func<T, bool>> ("where clause") with and/or

First, I must say that I have read several post about this at StackOverflow but I cannot get the desired result.

Let me explain the context (simplified): I'm using Linq-to-SQL to query customers with recent visits to the store and (optionally) get only those with certain amount of payments. Suppose I have a model with client, visits and payments classes.

So, focusing on the Where expression, I'm trying this:

Expression<Func<Entityes.Clients, bool>> filter = null;

filter = c => 
          c.Visits.Any(v => v.VisitDate > DateTime.Now.Date.AddMonths(-(int)visitsSince));


if (minPayment.HasValue && minPayment.Value > 0)
{
     filter.And(
               c => c.Payments.Sum(p => p.Quantity) > minPayment.Value);
}

The filter.And method is an extension method, recommended at this forum, below you can see the definition:

public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1,
                                            Expression<Func<T, bool>> expression2)
{
  InvocationExpression invokedExpression =
      Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());

  return Expression.Lambda<Func<T, bool>>
      (Expression.And(expression1.Body, invokedExpression), expression1.Parameters);
}

However, this doesn't work for me as expected and results are not filtered by payment amount. There is no error with data or linq-to-sql model because this code works fine:

filter = c => 
           c.Visits.Any(v => v.VisitDate > DateTime.Now.Date.AddMonths(-(int)visitsSince)))
             && c => c.Payments.Sum(p => p.Quantity) > minPayment.Value;

However, I don't want to use the last code because I have some more complex scenarios in which I need to build the filter expression step-by-step with an 'and/or' combination of each part.

PD: I'm a "ADO.Net DataSets" guy trying to learn Linq-to-SQL and soon Entity Framework, I hope to be useful to the StackOverflow community soon.

like image 372
Fran CD Avatar asked Feb 21 '12 21:02

Fran CD


1 Answers

You are not assigning the result of Anding to anything.

I suppose the respective part of your code should read as following:

if (minPayment.HasValue && minPayment.Value > 0)
{
   filter = filter.And(
            c => c.Payments.Sum(p => p.Quantity) > minPayment.Value);
}

The thing is that your (or SO's as you mentioned) And function returns the expression containing the conjunction of two expression. It does not alter the object it is invoked on.

like image 170
Krizz Avatar answered Oct 03 '22 18:10

Krizz