Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ "'s' is not in scope" when creating where clause dynamically

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");
    }
}
like image 573
Johnie Karr Avatar asked Jan 25 '26 07:01

Johnie Karr


1 Answers

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.

like image 197
CassOnMars Avatar answered Jan 27 '26 21:01

CassOnMars



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!