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");
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With