3

So, I'm getting the error that's in the title. I'll jump straight into the relevant code. First, the manual creation of the where statement (which does work) and then the dynamic creation which does not work. Both create the same queryExpression.

First, the queryExpression that is generated with both methods:

{Table(Products).Select
  (s => new SalesData() {
    ProductID = s.ProductID,
    StoreName = s.StoreName, 
    Count = s.Count
}).Where(s => (s.Count > 500))}

Now, the manual method that does work:

IQueryable<SalesData> data = ( from s in sales.Products
                               select new SalesData
                               {
                                   ProductID = s.ProductID,
                                   StoreName = s.StoreName,
                                   Count = s.Count
                               } ).AsQueryable<SalesData>();

data = data.Where(s => s.Count > 500);

this.dataGridView1.DataSource = null;

this.dataGridView1.DataSource = (from d in data
                                 select new
                                 {
                                     d.ProductID,
                                     d.StoreName,
                                     d.Count
                                 } );

This works as expected; my DataGridView is populated with the data.

Now, to create the where clause dynamically:

IQueryable<SalesData> data = ( from s in sales.Products
                               select new SalesData
                               {
                                   ProductID = s.ProductID,
                                   StoreName = s.StoreName,
                                   Count = s.Count
                               } ).AsQueryable<SalesData>();

if (this.filter.Predicate != null)
{
    Expression<Func<SalesData, bool>> lambda =
        Expression.Lambda<Func<SalesData, bool>>(this.filter.Predicate,
            new ParameterExpression[] { this.filter.PE });

    data = data.Where(lambda);
}

this.dataGridView1.DataSource = null;

this.dataGridView1.DataSource = (from d in data  <---- fails here
                                 select new
                                 {
                                     d.ProductID,
                                     d.StoreName,
                                     d.Count
                                 } );

The only thing that is different is that in the second snippet I'm creating the lambda expression dynamically. I've noted where it fails in the second snippet.

Using the debugger I can see the queryExpression for data and it is the same with both methods, so I don't think my problem is with my actual expression creation. If that code is needed I can post it here.

My question is, what am I doing wrong and how do I fix it?

Edit: Here is the function that gives filter.Predicate it's value:

public static Expression GetPredicate(List<FilterItem> itemList, ParameterExpression pe)
{
    List<Expression> expressions = new List<Expression>();
    List<string> combiners = new List<string>();

    foreach (FilterItem item in itemList)
    {
        Expression left = Expression.PropertyOrField(pe, item.Field);
        Expression right = Expression.Constant(Convert.ToInt32(item.Value), typeof(int));

        expressions.Add(Expression.GreaterThan(left, right));
        combiners.Add(item.Combiner);
    }

    int expressionCount = expressions.Count();
    Expression predicateBody = expressions[0];

    if (expressionCount > 1)
    {
        for (int x = 1; x <= expressionCount; x++)
        {
            switch (combiners[x - 1])
            {
                case "AND":
                    predicateBody = Expression.And(predicateBody, expressions[x]);
                    break;
                case "OR":
                    predicateBody = Expression.Or(predicateBody, expressions[x]);
                    break;
                default:
                    break;
            }
        }
    }

    return predicateBody;
}

Inside filter I have:

this.Predicate = BuildPredicate.GetPredicate(this.filterList, this.PE);

this.PE is:

public ParameterExpression PE
{
    get
    {
        return Expression.Parameter(typeof(SalesData), "s");
    }
}
Johnie Karr
  • 2,744
  • 2
  • 35
  • 44
  • 1
    What is the type and value of `filter.Predicate`? Also note that just because two lambda parameters are called the same, they are not equal from the expression point of view... – SWeko Dec 15 '11 at 14:23
  • filter.Predicate is type Expression and debugger says the value is {(s.Count > 500)} – Johnie Karr Dec 15 '11 at 14:28
  • Take a look at http://stackoverflow.com/questions/6736505/how-to-combine-two-lambdas – SWeko Dec 15 '11 at 14:39
  • Where does filter.Predicate have it's value set. All the information about why it doesn't work is now on this page, but not why it was set to something that won't work in the first place. – Jon Hanna Dec 15 '11 at 14:45
  • @JonHanna I updated my question to include how filter.Predicate gets it's value, and also filter.PE – Johnie Karr Dec 15 '11 at 14:55
  • It might also be worth noting that this is my first ever attempt at this. I used http://msdn.microsoft.com/en-us/library/bb882637.aspx and http://marcgravell.blogspot.com/2008/10/express-yourself.html as resources to get this far. – Johnie Karr Dec 15 '11 at 15:01

2 Answers2

5

From the father of C#, Anders Hejlsberg:

Parameters are referenced in expressions through their object identity, not by comparing their names. In fact, from an expression tree's point of view, the name of a parameter is purely informational. The reason for this design is the same reason that types are referenced through their System.Type objects and not their names--expression trees are fully bound and are not in the business of implementing name lookup rules (which may differ from language to language).

From MSDN Forums

The short and long of it is that filter.Predicate has a value of {(s.Count > 500)} but this doesn't mean that s has meaning here by sharing a name with the initial LINQ expression.

CassOnMars
  • 6,153
  • 2
  • 32
  • 47
0

I was able to solve my problem thanks to the dialog on this page and using Predicate Builder.

A better method for what I'm trying to do can be found at Scott Gu's site. This is better for my purposes because I need to determine the field and the value dynamically, plus allow for grouping (easier with this method).

Johnie Karr
  • 2,744
  • 2
  • 35
  • 44