Pass a parameter to the reusable Expression in a Entity Framework - c#

I want to declare and reuse Expression with filter by variable y. In a method I have something like following:
Expression<Func<Item, int, bool>> exFilter = (x, y) => x.Item.Id == y;
Further on, in a code I'm trying to use declared expression (exFilter)
return context.Item.Select(x => new { data = exFilter.Where(exFilter))
Q: How do I pass parameter to the exFilter? I want to do select filtered by every item in a list(x).
This is just a sample what I'm trying to figure out. The problem and query is much bigger and complicated.

You can use LinqKit to reuse the expression that you have. Here is an example:
var result =
context.Item //The DbSet
.AsExpandable() //This method is defined in LinqKit and allows for expression expansion
.Where(x => exFilter.Invoke(x, 2)) //LinqKit will know how to translate this into an expression
.ToList();
I am using the value 2 here as an example.

You can rewrite you code like this:
Expression<Func<Item, bool>> exFilter(int y){ return (x) => x.item.Id == y;}
And use it like this:
int paramY = 456;
return context.Item.Select(exFilter(paramY))

You can try something like this:
public class Item
{
public Item(String str, Int32 #int)
{
this.StrValue = str;
this.IntValue = #int;
}
public String StrValue { get; }
public Int32 IntValue { get; }
public override string ToString() =>
$"{this.IntValue} = '{this.StrValue}'";
}
public static class ExpressionExtensions
{
public static Expression<Func<TItem, TResult>> Curry<TItem, TCurry, TResult>(
this Expression<Func<TItem, TCurry, TResult>> function,
TCurry value)
{
if (function == null)
throw new ArgumentNullException(paramName: nameof(function));
var itemParameter = Expression.Parameter(typeof(TItem));
var valueConstant = Expression.Constant(value);
return Expression.Lambda<Func<TItem, TResult>>(
Expression.Invoke(
function,
new Expression[]
{
itemParameter,
valueConstant
}),
new[] { itemParameter });
}
}
...
var items = new[]
{
new Item("one", 1),
new Item("two", 2),
new Item("two again", 2),
};
Expression<Func<Item, Int32, Boolean>> predicate = (item, intValue) =>
item.IntValue == intValue;
var curriedPredicate = predicate.Curry(2);
var filtered = items
.AsQueryable<Item>()
.Where(curriedPredicate)
.ToArray();
foreach (var item in filtered)
{
Console.WriteLine(item);
}

Related

Apply Where conditionally (OR between them) LINQ

I have filters in my asp.net project and want to add expression to this list with condition:
Expression<Func<MyModel, bool>> func;
var list = new List<Expression<Func<MyModel, bool>>>();
I want to conditionally apply Where (OR between them). for example:
if(sth){
func = p => p.a <= b;
list.Add(func);
}
if (sth else){
func = p => p.c >= d;
list.Add(func);
}
var fq = Session.Query<MyModel>();
fq = list.Aggregate(fq, (current, expression) => current.Where(expression));
How can I do this?
You can build an extension method to merge two condition expressions using OR relationship like this:
public static class Extensions
{
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
{
var parameter = one.Parameters[0];
var visitor = new ReplaceParameterVisitor(parameter);
another = (Expression<Func<T, bool>>)visitor.Visit(another);
var body = Expression.Or(one.Body, another.Body);
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
}
class ReplaceParameterVisitor : ExpressionVisitor
{
public ParameterExpression NewParameter { get; private set; }
public ReplaceParameterVisitor(ParameterExpression newParameter)
{
this.NewParameter = newParameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return this.NewParameter;
}
}
Usage and test code:
Expression<Func<int, bool>> condition1 = x => x > 8;
Expression<Func<int, bool>> condition2 = y => y < 3;
var condition = condition1.Or(condition2);
var result = Enumerable
.Range(1, 10)
.Where(condition.Compile())
.ToList(); //1,2,9,10
Looks like you could do this easily with an extension method
public static class EnumerableExtensions
{
public static IEnumerable<T> ConditionalWhere<T>(this IEnumerable<T> list,
bool condition, Func<T,bool> predicate)
{
if(!condition)
return list;
return list.Where(predicate);
}
}
Usage would be:
var fq = Session.Query<MyModel>();
var result = fq.ConditionalWhere(sth, p => p.a <= b)
.ConditionalWhere(sth_else, p => p.c >= d);
I built a bit of code to showcase Predicate<> while trying to stick to your program structure:
using System;
using System.Collections.Generic;
using System.Linq;
namespace SOTests
{
public class MyModel
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
private static int ControlId;
private static string ControlName;
static void Main(string[] args)
{
var idPred = new Predicate<MyModel>(m => m.Id > ControlId);
var namePred = new Predicate<MyModel>(m => m.Name == ControlName);
var list = new List<MyModel>();
if (true) // TODO: do id check?
{
list = list.Where(m => idPred.Invoke(m)).ToList();
}
if (true) // TODO: do name check?
{
list = list.Where(m => namePred.Invoke(m)).ToList();
}
//var fq = Session.Query<MyModel>();
//fq = list;
}
}
}
I commented out the Session bit not knowing what kind of storage abstraction it represents (and the code wouldn't compile).
The code should explain itself and it's not tested.
It can be much more elegant, but you should state more clearly what your requirements are for that.
Thanks all, I found the solution : OrElse
Expression<Func<MyModel, bool>> OrExpressionFunction(Expression<Func<MyModel, bool>> exp1, Expression<Func<MyModel, bool>> exp2)
{
ParameterExpression p = exp1.Parameters.Single();
return Expression.Lambda<Func<MyModel, bool>>(
Expression.OrElse(exp1.Body, exp2.Body), p);
}
then:
Expression<Func<MyModel, bool>> MyExp = null;
if(sth){
func = p => p.a <= b;
MyExp= OrExpressionFunction(func, MyExp);
}
if (sth else){
func = p => p.c >= d;
MyExp= OrExpressionFunction(func, MyExp);
}
list.Add(MyExp);

How to append Linq Expression [duplicate]

Given a class structure like this:
public class GrandParent
{
public Parent Parent { get; set;}
}
public class Parent
{
public Child Child { get; set;}
}
public class Child
{
public string Name { get; set;}
}
and the following method signature:
Expression<Func<TOuter, TInner>> Combine (Expression<Func<TOuter, TMiddle>>> first, Expression<Func<TMiddle, TInner>> second);
How can I implement said method so that I can call it like this:
Expression<Func<GrandParent, Parent>>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> output = Combine(myFirst, mySecond);
such that output ends up as:
gp => gp.Parent.Child.Name
Is this possible?
The contents of each Func will only ever be a MemberAccess. I'd rather not end up with output being a nested function call.
Thanks
OK; pretty long snippet, but here's a starter for an expression-rewriter; it doesn't handle a few cases yet (I'll fix it later), but it works for the example given and a lot of others:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
public class GrandParent
{
public Parent Parent { get; set; }
}
public class Parent
{
public Child Child { get; set; }
public string Method(string s) { return s + "abc"; }
}
public class Child
{
public string Name { get; set; }
}
public static class ExpressionUtils
{
public static Expression<Func<T1, T3>> Combine<T1, T2, T3>(
this Expression<Func<T1, T2>> outer, Expression<Func<T2, T3>> inner, bool inline)
{
var invoke = Expression.Invoke(inner, outer.Body);
Expression body = inline ? new ExpressionRewriter().AutoInline(invoke) : invoke;
return Expression.Lambda<Func<T1, T3>>(body, outer.Parameters);
}
}
public class ExpressionRewriter
{
internal Expression AutoInline(InvocationExpression expression)
{
isLocked = true;
if(expression == null) throw new ArgumentNullException("expression");
LambdaExpression lambda = (LambdaExpression)expression.Expression;
ExpressionRewriter childScope = new ExpressionRewriter(this);
var lambdaParams = lambda.Parameters;
var invokeArgs = expression.Arguments;
if (lambdaParams.Count != invokeArgs.Count) throw new InvalidOperationException("Lambda/invoke mismatch");
for(int i = 0 ; i < lambdaParams.Count; i++) {
childScope.Subst(lambdaParams[i], invokeArgs[i]);
}
return childScope.Apply(lambda.Body);
}
public ExpressionRewriter()
{
subst = new Dictionary<Expression, Expression>();
}
private ExpressionRewriter(ExpressionRewriter parent)
{
if (parent == null) throw new ArgumentNullException("parent");
subst = new Dictionary<Expression, Expression>(parent.subst);
inline = parent.inline;
}
private bool isLocked, inline;
private readonly Dictionary<Expression, Expression> subst;
private void CheckLocked() {
if(isLocked) throw new InvalidOperationException(
"You cannot alter the rewriter after Apply has been called");
}
public ExpressionRewriter Subst(Expression from,
Expression to)
{
CheckLocked();
subst.Add(from, to);
return this;
}
public ExpressionRewriter Inline() {
CheckLocked();
inline = true;
return this;
}
public Expression Apply(Expression expression)
{
isLocked = true;
return Walk(expression) ?? expression;
}
private static IEnumerable<Expression> CoalesceTerms(
IEnumerable<Expression> sourceWithNulls, IEnumerable<Expression> replacements)
{
if(sourceWithNulls != null && replacements != null) {
using(var left = sourceWithNulls.GetEnumerator())
using (var right = replacements.GetEnumerator())
{
while (left.MoveNext() && right.MoveNext())
{
yield return left.Current ?? right.Current;
}
}
}
}
private Expression[] Walk(IEnumerable<Expression> expressions) {
if(expressions == null) return null;
return expressions.Select(expr => Walk(expr)).ToArray();
}
private static bool HasValue(Expression[] expressions)
{
return expressions != null && expressions.Any(expr => expr != null);
}
// returns null if no need to rewrite that branch, otherwise
// returns a re-written branch
private Expression Walk(Expression expression)
{
if (expression == null) return null;
Expression tmp;
if (subst.TryGetValue(expression, out tmp)) return tmp;
switch(expression.NodeType) {
case ExpressionType.Constant:
case ExpressionType.Parameter:
{
return expression; // never a need to rewrite if not already matched
}
case ExpressionType.MemberAccess:
{
MemberExpression me = (MemberExpression)expression;
Expression target = Walk(me.Expression);
return target == null ? null : Expression.MakeMemberAccess(target, me.Member);
}
case ExpressionType.Add:
case ExpressionType.Divide:
case ExpressionType.Multiply:
case ExpressionType.Subtract:
case ExpressionType.AddChecked:
case ExpressionType.MultiplyChecked:
case ExpressionType.SubtractChecked:
case ExpressionType.And:
case ExpressionType.Or:
case ExpressionType.ExclusiveOr:
case ExpressionType.Equal:
case ExpressionType.NotEqual:
case ExpressionType.AndAlso:
case ExpressionType.OrElse:
case ExpressionType.Power:
case ExpressionType.Modulo:
case ExpressionType.GreaterThan:
case ExpressionType.GreaterThanOrEqual:
case ExpressionType.LessThan:
case ExpressionType.LessThanOrEqual:
case ExpressionType.LeftShift:
case ExpressionType.RightShift:
case ExpressionType.Coalesce:
case ExpressionType.ArrayIndex:
{
BinaryExpression binExp = (BinaryExpression)expression;
Expression left = Walk(binExp.Left), right = Walk(binExp.Right);
return (left == null && right == null) ? null : Expression.MakeBinary(
binExp.NodeType, left ?? binExp.Left, right ?? binExp.Right, binExp.IsLiftedToNull,
binExp.Method, binExp.Conversion);
}
case ExpressionType.Not:
case ExpressionType.UnaryPlus:
case ExpressionType.Negate:
case ExpressionType.NegateChecked:
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
case ExpressionType.TypeAs:
case ExpressionType.ArrayLength:
{
UnaryExpression unExp = (UnaryExpression)expression;
Expression operand = Walk(unExp.Operand);
return operand == null ? null : Expression.MakeUnary(unExp.NodeType, operand,
unExp.Type, unExp.Method);
}
case ExpressionType.Conditional:
{
ConditionalExpression ce = (ConditionalExpression)expression;
Expression test = Walk(ce.Test), ifTrue = Walk(ce.IfTrue), ifFalse = Walk(ce.IfFalse);
if (test == null && ifTrue == null && ifFalse == null) return null;
return Expression.Condition(test ?? ce.Test, ifTrue ?? ce.IfTrue, ifFalse ?? ce.IfFalse);
}
case ExpressionType.Call:
{
MethodCallExpression mce = (MethodCallExpression)expression;
Expression instance = Walk(mce.Object);
Expression[] args = Walk(mce.Arguments);
if (instance == null && !HasValue(args)) return null;
return Expression.Call(instance, mce.Method, CoalesceTerms(args, mce.Arguments));
}
case ExpressionType.TypeIs:
{
TypeBinaryExpression tbe = (TypeBinaryExpression)expression;
tmp = Walk(tbe.Expression);
return tmp == null ? null : Expression.TypeIs(tmp, tbe.TypeOperand);
}
case ExpressionType.New:
{
NewExpression ne = (NewExpression)expression;
Expression[] args = Walk(ne.Arguments);
if (HasValue(args)) return null;
return ne.Members == null ? Expression.New(ne.Constructor, CoalesceTerms(args, ne.Arguments))
: Expression.New(ne.Constructor, CoalesceTerms(args, ne.Arguments), ne.Members);
}
case ExpressionType.ListInit:
{
ListInitExpression lie = (ListInitExpression)expression;
NewExpression ctor = (NewExpression)Walk(lie.NewExpression);
var inits = lie.Initializers.Select(init => new
{
Original = init,
NewArgs = Walk(init.Arguments)
}).ToArray();
if (ctor == null && !inits.Any(init => HasValue(init.NewArgs))) return null;
ElementInit[] initArr = inits.Select(init => Expression.ElementInit(
init.Original.AddMethod, CoalesceTerms(init.NewArgs, init.Original.Arguments))).ToArray();
return Expression.ListInit(ctor ?? lie.NewExpression, initArr);
}
case ExpressionType.NewArrayBounds:
case ExpressionType.NewArrayInit:
/* not quite right... leave as not-implemented for now
{
NewArrayExpression nae = (NewArrayExpression)expression;
Expression[] expr = Walk(nae.Expressions);
if (!HasValue(expr)) return null;
return expression.NodeType == ExpressionType.NewArrayBounds
? Expression.NewArrayBounds(nae.Type, CoalesceTerms(expr, nae.Expressions))
: Expression.NewArrayInit(nae.Type, CoalesceTerms(expr, nae.Expressions));
}*/
case ExpressionType.Invoke:
case ExpressionType.Lambda:
case ExpressionType.MemberInit:
case ExpressionType.Quote:
throw new NotImplementedException("Not implemented: " + expression.NodeType);
default:
throw new NotSupportedException("Not supported: " + expression.NodeType);
}
}
}
static class Program
{
static void Main()
{
Expression<Func<GrandParent, Parent>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> outputWithInline = myFirst.Combine(mySecond, false);
Expression<Func<GrandParent, string>> outputWithoutInline = myFirst.Combine(mySecond, true);
Expression<Func<GrandParent, string>> call =
ExpressionUtils.Combine<GrandParent, Parent, string>(
gp => gp.Parent, p => p.Method(p.Child.Name), true);
unchecked
{
Expression<Func<double, double>> mathUnchecked =
ExpressionUtils.Combine<double, double, double>(x => (x * x) + x, x => x - (x / x), true);
}
checked
{
Expression<Func<double, double>> mathChecked =
ExpressionUtils.Combine<double, double, double>(x => x - (x * x) , x => (x / x) + x, true);
}
Expression<Func<int,int>> bitwise =
ExpressionUtils.Combine<int, int, int>(x => (x & 0x01) | 0x03, x => x ^ 0xFF, true);
Expression<Func<int, bool>> logical =
ExpressionUtils.Combine<int, bool, bool>(x => x == 123, x => x != false, true);
Expression<Func<int[][], int>> arrayAccess =
ExpressionUtils.Combine<int[][], int[], int>(x => x[0], x => x[0], true);
Expression<Func<string, bool>> isTest =
ExpressionUtils.Combine<string,object,bool>(s=>s, s=> s is Regex, true);
Expression<Func<List<int>>> f = () => new List<int>(new int[] { 1, 1, 1 }.Length);
Expression<Func<string, Regex>> asTest =
ExpressionUtils.Combine<string, object, Regex>(s => s, s => s as Regex, true);
var initTest = ExpressionUtils.Combine<int, int[], List<int>>(i => new[] {i,i,i},
arr => new List<int>(arr.Length), true);
var anonAndListTest = ExpressionUtils.Combine<int, int, List<int>>(
i => new { age = i }.age, i => new List<int> {i, i}, true);
/*
var arrBoundsInit = ExpressionUtils.Combine<int, int[], int[]>(
i => new int[i], arr => new int[arr[0]] , true);
var arrInit = ExpressionUtils.Combine<int, int, int[]>(
i => i, i => new int[1] { i }, true);*/
}
}
I am assuming that your goal is to obtain the expression tree that you would have obtained, had you actually compiled the "combined" lambda. It's much easier to construct a new expression tree that simply invokes the given expression trees appropriately, but I assume that's not what you want.
extract the body of first, cast it to MemberExpression. Call this firstBody.
extract the body of second, call this secondBody
extract the parameter of first. Call this firstParam.
extract the parameter of second. Call this secondParam.
Now, the hard part. Write a visitor pattern implementation which searches through secondBody looking for the single usage of secondParam. (This will be much easier if you know that it's only member access expressions, but you can solve the problem in general.) When you find it, construct a new expression of the same type as its parent, substituting in firstBody for the parameter. Continue to rebuild the transformed tree on the way back out; remember, all you have to rebuild is the "spine" of the tree that contains the parameter reference.
the result of the visitor pass will be a rewritten secondBody with no occurrences of secondParam, only occurences of expressions involving firstParam.
construct a new lambda expression with that body as its body, and firstParam as its param.
and you're done!
Matt Warren's blog might be a good thing for you to read. He designed and implemented all this stuff and has written a lot about ways to rewrite expression trees effectively. (I only did the compiler end of things.)
UPDATE:
As this related answer points out, in .NET 4 there is now a base class for expression rewriters that makes this sort of thing a lot easier.
I'm not sure what you mean by it not being a nested function call, but this will do the trick - with an example:
using System;
using System.IO;
using System.Linq.Expressions;
class Test
{
static Expression<Func<TOuter, TInner>> Combine<TOuter, TMiddle, TInner>
(Expression<Func<TOuter, TMiddle>> first,
Expression<Func<TMiddle, TInner>> second)
{
var parameter = Expression.Parameter(typeof(TOuter), "x");
var firstInvoke = Expression.Invoke(first, new[] { parameter });
var secondInvoke = Expression.Invoke(second, new[] { firstInvoke} );
return Expression.Lambda<Func<TOuter, TInner>>(secondInvoke, parameter);
}
static void Main()
{
Expression<Func<int, string>> first = x => (x + 1).ToString();
Expression<Func<string, StringReader>> second = y => new StringReader(y);
Expression<Func<int, StringReader>> output = Combine(first, second);
Func<int, StringReader> compiled = output.Compile();
var reader = compiled(10);
Console.WriteLine(reader.ReadToEnd());
}
}
I don't know how efficient the generated code will be compared with a single lambda expression, but I suspect it won't be too bad.
For a complete solution have a look at LINQKit:
Expression<Func<GrandParent, string>> output = gp => mySecond.Invoke(myFirst.Invoke(gp));
output = output.Expand().Expand();
output.ToString() prints out
gp => gp.Parent.Child.Name
whereas Jon Skeet's solution yields
x => Invoke(p => p.Child.Name,Invoke(gp => gp.Parent,x))
I guess that's what you're referring to as 'nested function calls'.
Try this:
public static Expression<Func<TOuter, TInner>> Combine<TOuter, TMiddle, TInner>(
Expression<Func<TOuter, TMiddle>> first,
Expression<Func<TMiddle, TInner>> second)
{
return x => second.Compile()(first.Compile()(x));
}
and the usage:
Expression<Func<GrandParent, Parent>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> output = Combine(myFirst, mySecond);
var grandParent = new GrandParent
{
Parent = new Parent
{
Child = new Child
{
Name = "child name"
}
}
};
var childName = output.Compile()(grandParent);
Console.WriteLine(childName); // prints "child name"
public static Expression<Func<T, TResult>> And<T, TResult>(this Expression<Func<T, TResult>> expr1, Expression<Func<T, TResult>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, TResult>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}
After a half-day's digging came up with the following solution (much simpler than the accepted answer):
For generic lambda composition:
public static Expression<Func<X, Z>> Compose<X, Y, Z>(Expression<Func<Y, Z>> f, Expression<Func<X, Y>> g)
{
return Expression.Lambda<Func<X, Z>>(Expression.Invoke(f, Expression.Invoke(g, g.Parameters[0])), g.Parameters);
}
This combines two expressions in one, i.e. applies the first expression to the result of the second.
So if we have f(y) and g(x), combine(f,g)(x) === f(g(x))
Transitive and associative, so the combinator can be chained
More specifically, for property access (needed for MVC/EF):
public static Expression<Func<X, Z>> Property<X, Y, Z>(Expression<Func<X, Y>> fObj, Expression<Func<Y, Z>> fProp)
{
return Expression.Lambda<Func<X, Z>>(Expression.Property(fObj.Body, (fProp.Body as MemberExpression).Member as PropertyInfo), fObj.Parameters);
}
Note: fProp must be a simple property access expression, such as x => x.Prop.
fObj can be any expression (but must be MVC-compatible)
With a toolkit called Layer Over LINQ, there's an extension method that does exactly this, combines two expressions to create a new one suitable for use in LINQ to Entities.
Expression<Func<GrandParent, Parent>>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> output = myFirst.Chain(mySecond);

LINQ expressions. Variable 'p' of type referenced from scope, but it is not defined

I'm building a LINQ query dynamically with this code.
It seems to work, but when i have more than one searchString in my search, (so when multiple expressions are added, i get the following error:
Variable 'p' of type referenced from scope, but it is not defined**
I guess i can only define /use p once. But, if so, i need to alter my code a bit. Can anyone point me in the right direction here?
if (searchStrings != null)
{
foreach (string searchString in searchStrings)
{
Expression<Func<Product, bool>> containsExpression = p => p.Name.Contains(searchString);
filterExpressions.Add(containsExpression);
}
}
Func<Expression, Expression, BinaryExpression>[] operators = new Func<Expression, Expression, BinaryExpression>[] { Expression.AndAlso };
Expression<Func<Product, bool>> filters = this.CombinePredicates<Product>(filterExpressions, operators);
IQueryable<Product> query = cachedProductList.AsQueryable().Where(filters);
query.Take(itemLimit).ToList(); << **error when the query executes**
public Expression<Func<T, bool>> CombinePredicates<T>(IList<Expression<Func<T, bool>>> predicateExpressions, Func<Expression, Expression, BinaryExpression> logicalFunction)
{
Expression<Func<T, bool>> filter = null;
if (predicateExpressions.Count > 0)
{
Expression<Func<T, bool>> firstPredicate = predicateExpressions[0];
Expression body = firstPredicate.Body;
for (int i = 1; i < predicateExpressions.Count; i++)
{
body = logicalFunction(body, predicateExpressions[i].Body);
}
filter = Expression.Lambda<Func<T, bool>>(body, firstPredicate.Parameters);
}
return filter;
}
Simplifying, here are several lines which you are trying to do (I use string instead Product etc, but idea is the same):
Expression<Func<string, bool>> c1 = x => x.Contains("111");
Expression<Func<string, bool>> c2 = y => y.Contains("222");
var sum = Expression.AndAlso(c1.Body, c2.Body);
var sumExpr = Expression.Lambda(sum, c1.Parameters);
sumExpr.Compile(); // exception here
Please notice how I expanded your foreach into two expressions with x and y - this is exactly how it looks like for compiler, that are different parameters.
In other words, you are trying to do something like this:
x => x.Contains("...") && y.Contains("...");
and compiler wondering what is that 'y' variable??
To fix it, we need to use exactly the same parameter (not just name, but also reference) for all expressions. We can fix this simplified code like this:
Expression<Func<string, bool>> c1 = x => x.Contains("111");
Expression<Func<string, bool>> c2 = y => y.Contains("222");
var sum = Expression.AndAlso(c1.Body, Expression.Invoke(c2, c1.Parameters[0])); // here is the magic
var sumExpr = Expression.Lambda(sum, c1.Parameters);
sumExpr.Compile(); //ok
So, fixing you original code would be like:
internal static class Program
{
public class Product
{
public string Name;
}
private static void Main(string[] args)
{
var searchStrings = new[] { "111", "222" };
var cachedProductList = new List<Product>
{
new Product{Name = "111 should not match"},
new Product{Name = "222 should not match"},
new Product{Name = "111 222 should match"},
};
var filterExpressions = new List<Expression<Func<Product, bool>>>();
foreach (string searchString in searchStrings)
{
Expression<Func<Product, bool>> containsExpression = x => x.Name.Contains(searchString); // NOT GOOD
filterExpressions.Add(containsExpression);
}
var filters = CombinePredicates<Product>(filterExpressions, Expression.AndAlso);
var query = cachedProductList.AsQueryable().Where(filters);
var list = query.Take(10).ToList();
foreach (var product in list)
{
Console.WriteLine(product.Name);
}
}
public static Expression<Func<T, bool>> CombinePredicates<T>(IList<Expression<Func<T, bool>>> predicateExpressions, Func<Expression, Expression, BinaryExpression> logicalFunction)
{
Expression<Func<T, bool>> filter = null;
if (predicateExpressions.Count > 0)
{
var firstPredicate = predicateExpressions[0];
Expression body = firstPredicate.Body;
for (int i = 1; i < predicateExpressions.Count; i++)
{
body = logicalFunction(body, Expression.Invoke(predicateExpressions[i], firstPredicate.Parameters));
}
filter = Expression.Lambda<Func<T, bool>>(body, firstPredicate.Parameters);
}
return filter;
}
}
But notice the output:
222 should not match
111 222 should match
Not something you may expect.. This is result of using searchString in foreach, which should be rewritten in the following way:
...
foreach (string searchString in searchStrings)
{
var name = searchString;
Expression<Func<Product, bool>> containsExpression = x => x.Name.Contains(name);
filterExpressions.Add(containsExpression);
}
...
And here is output:
111 222 should match
IMHO, no need to make the list:
var filterExpressions = new List<Expression<Func<Product, bool>>>()
You may easily live with the following in Visitor class:
public class FilterConverter : IFilterConverterVisitor<Filter> {
private LambdaExpression ConditionClausePredicate { get; set; }
private ParameterExpression Parameter { get; set; }
public void Visit(Filter filter) {
if (filter == null) {
return;
}
if (this.Parameter == null) {
this.Parameter = Expression.Parameter(filter.BaseType, "x");
}
ConditionClausePredicate = And(filter);
}
public Delegate GetConditionClause() {
if (ConditionClausePredicate != null) {
return ConditionClausePredicate.Compile();
}
return null;
}
private LambdaExpression And(Filter filter) {
if (filter.BaseType == null || string.IsNullOrWhiteSpace(filter.FlattenPropertyName)) {
//Something is wrong, passing by current filter
return ConditionClausePredicate;
}
var conditionType = filter.GetCondition();
var propertyExpression = filter.BaseType.GetFlattenPropertyExpression(filter.FlattenPropertyName, this.Parameter);
switch (conditionType) {
case FilterCondition.Equal: {
var matchValue = TypeDescriptor.GetConverter(propertyExpression.ReturnType).ConvertFromString(filter.Match);
var propertyValue = Expression.Constant(matchValue, propertyExpression.ReturnType);
var equalExpression = Expression.Equal(propertyExpression.Body, propertyValue);
if (ConditionClausePredicate == null) {
ConditionClausePredicate = Expression.Lambda(equalExpression, this.Parameter);
} else {
ConditionClausePredicate = Expression.Lambda(Expression.And(ConditionClausePredicate.Body, equalExpression), this.Parameter);
}
break;
}
// and so on...
}
}
The code is not optimal, I know, I'm a beginner and a lot of everything to be implemented... But this stuff does work. The idea is to have the only ParameterExpression per Visitor class, then to construct expressions using this parameter. After, just concatenate all expressions per one LambdaExpression clause and compile to delegate, when needed.

Combine several similar SELECT-expressions into a single expression

How to combine several similar SELECT-expressions into a single expression?
private static Expression<Func<Agency, AgencyDTO>> CombineSelectors(params Expression<Func<Agency, AgencyDTO>>[] selectors)
{
// ???
return null;
}
private void Query()
{
Expression<Func<Agency, AgencyDTO>> selector1 = x => new AgencyDTO { Name = x.Name };
Expression<Func<Agency, AgencyDTO>> selector2 = x => new AgencyDTO { Phone = x.PhoneNumber };
Expression<Func<Agency, AgencyDTO>> selector3 = x => new AgencyDTO { Location = x.Locality.Name };
Expression<Func<Agency, AgencyDTO>> selector4 = x => new AgencyDTO { EmployeeCount = x.Employees.Count() };
using (RealtyContext context = Session.CreateContext())
{
IQueryable<AgencyDTO> agencies = context.Agencies.Select(CombineSelectors(selector3, selector4));
foreach (AgencyDTO agencyDTO in agencies)
{
// do something..;
}
}
}
Not simple; you need to rewrite all the expressions - well, strictly speaking you can recycle most of one of them, but the problem is that you have different x in each (even though it looks the same), hence you need to use a visitor to replace all the parameters with the final x. Fortunately this isn't too bad in 4.0:
static void Main() {
Expression<Func<Agency, AgencyDTO>> selector1 = x => new AgencyDTO { Name = x.Name };
Expression<Func<Agency, AgencyDTO>> selector2 = x => new AgencyDTO { Phone = x.PhoneNumber };
Expression<Func<Agency, AgencyDTO>> selector3 = x => new AgencyDTO { Location = x.Locality.Name };
Expression<Func<Agency, AgencyDTO>> selector4 = x => new AgencyDTO { EmployeeCount = x.Employees.Count() };
// combine the assignments from the 4 selectors
var convert = Combine(selector1, selector2, selector3, selector4);
// sample data
var orig = new Agency
{
Name = "a",
PhoneNumber = "b",
Locality = new Location { Name = "c" },
Employees = new List<Employee> { new Employee(), new Employee() }
};
// check it
var dto = new[] { orig }.AsQueryable().Select(convert).Single();
Console.WriteLine(dto.Name); // a
Console.WriteLine(dto.Phone); // b
Console.WriteLine(dto.Location); // c
Console.WriteLine(dto.EmployeeCount); // 2
}
static Expression<Func<TSource, TDestination>> Combine<TSource, TDestination>(
params Expression<Func<TSource, TDestination>>[] selectors)
{
var zeroth = ((MemberInitExpression)selectors[0].Body);
var param = selectors[0].Parameters[0];
List<MemberBinding> bindings = new List<MemberBinding>(zeroth.Bindings.OfType<MemberAssignment>());
for (int i = 1; i < selectors.Length; i++)
{
var memberInit = (MemberInitExpression)selectors[i].Body;
var replace = new ParameterReplaceVisitor(selectors[i].Parameters[0], param);
foreach (var binding in memberInit.Bindings.OfType<MemberAssignment>())
{
bindings.Add(Expression.Bind(binding.Member,
replace.VisitAndConvert(binding.Expression, "Combine")));
}
}
return Expression.Lambda<Func<TSource, TDestination>>(
Expression.MemberInit(zeroth.NewExpression, bindings), param);
}
class ParameterReplaceVisitor : ExpressionVisitor
{
private readonly ParameterExpression from, to;
public ParameterReplaceVisitor(ParameterExpression from, ParameterExpression to)
{
this.from = from;
this.to = to;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node == from ? to : base.VisitParameter(node);
}
}
This uses the constructor from the first expression found, so you might want to sanity-check that all of the others use trivial constructors in their respective NewExpressions. I've left that for the reader, though.
Edit: In the comments, #Slaks notes that more LINQ could make this shorter. He is of course right - a bit dense for easy reading, though:
static Expression<Func<TSource, TDestination>> Combine<TSource, TDestination>(
params Expression<Func<TSource, TDestination>>[] selectors)
{
var param = Expression.Parameter(typeof(TSource), "x");
return Expression.Lambda<Func<TSource, TDestination>>(
Expression.MemberInit(
Expression.New(typeof(TDestination).GetConstructor(Type.EmptyTypes)),
from selector in selectors
let replace = new ParameterReplaceVisitor(
selector.Parameters[0], param)
from binding in ((MemberInitExpression)selector.Body).Bindings
.OfType<MemberAssignment>()
select Expression.Bind(binding.Member,
replace.VisitAndConvert(binding.Expression, "Combine")))
, param);
}
If all of the selectors will only initialize AgencyDTO objects (like your example), you can cast the expressions to NewExpression instances, then call Expression.New with the Members of the expressions.
You'll also need an ExpressionVisitor to replace the ParameterExpressions from the original expressions with a single ParameterExpression for the expression you're creating.
In case anyone else stumbles upon this with a similar use case as mine (my selects targeted different classes based on the level of detail needed):
Simplified scenario:
public class BlogSummaryViewModel
{
public string Name { get; set; }
public static Expression<Func<Data.Blog, BlogSummaryViewModel>> Map()
{
return (i => new BlogSummaryViewModel
{
Name = i.Name
});
}
}
public class BlogViewModel : BlogSummaryViewModel
{
public int PostCount { get; set; }
public static Expression<Func<Data.Blog, BlogViewModel>> Map()
{
return (i => new BlogViewModel
{
Name = i.Name,
PostCount = i.Posts.Count()
});
}
}
I adapted the solution provided by #Marc Gravell like so:
public static class ExpressionMapExtensions
{
public static Expression<Func<TSource, TTargetB>> Concat<TSource, TTargetA, TTargetB>(
this Expression<Func<TSource, TTargetA>> mapA, Expression<Func<TSource, TTargetB>> mapB)
where TTargetB : TTargetA
{
var param = Expression.Parameter(typeof(TSource), "i");
return Expression.Lambda<Func<TSource, TTargetB>>(
Expression.MemberInit(
((MemberInitExpression)mapB.Body).NewExpression,
(new LambdaExpression[] { mapA, mapB }).SelectMany(e =>
{
var bindings = ((MemberInitExpression)e.Body).Bindings.OfType<MemberAssignment>();
return bindings.Select(b =>
{
var paramReplacedExp = new ParameterReplaceVisitor(e.Parameters[0], param).VisitAndConvert(b.Expression, "Combine");
return Expression.Bind(b.Member, paramReplacedExp);
});
})),
param);
}
private class ParameterReplaceVisitor : ExpressionVisitor
{
private readonly ParameterExpression original;
private readonly ParameterExpression updated;
public ParameterReplaceVisitor(ParameterExpression original, ParameterExpression updated)
{
this.original = original;
this.updated = updated;
}
protected override Expression VisitParameter(ParameterExpression node) => node == original ? updated : base.VisitParameter(node);
}
}
The Map method of the extended class then becomes:
public static Expression<Func<Data.Blog, BlogViewModel>> Map()
{
return BlogSummaryViewModel.Map().Concat(i => new BlogViewModel
{
PostCount = i.Posts.Count()
});
}

Expression tree modification problem

I have the following:
Expression<Func<Car, int>> myExpr = car => car.Wheel.Tyre.Pressure;
I want to remove the parameter, and make the first member the parameter for a sub-expression, so i end up with:
Expression<Func<Wheel, int>> mySubExpr = wheel => wheel.Tyre.Pressure;
This needs to work for any expression tree of the above format, including MemberExpression, MethodCallExpression and any other Expression which has a .Expression property. For example:
Expression<Func<Car, int>> myOtherExpr = car => car.GetRearLeftWheel().GetTyre().Pressure
or
Expression<Func<Car, int>> anotherExpr = car => car.Wheel.GetTyre().GetPressure();
How would I achieve this elegantly?
Thanks
Andrew
Start with the class from this page
Then sprinkle in this code and I think you have a solution (the test stuff was how I tested it, I think it is pretty much the same as what you did):
class Test
{
public Test()
{
Expression<Func<string, string>> trim2 = s => s.Substring(1).Substring(1);
var modifier = new PopModifier();
Expression<Func<string, string>> trim1 = (Expression<Func<string, string>>)modifier.Modify(trim2);
var test2 = trim2.Compile();
var test1 = trim1.Compile();
var input = "abc";
if (test2(input) != "c")
{
throw new Exception();
}
if (test1(input) != "bc")
{
throw new Exception();
}
}
}
public class PopModifier : ExpressionVisitor
{
bool didModify = false;
public Expression Modify(Expression expression)
{
return Visit(expression);
}
protected override Expression VisitMethodCall(MethodCallExpression m)
{
if (!didModify)
{
didModify = true;
return m.Object;
}
return base.VisitMethodCall(m);
}
}
Did you check out Metalinq and its EditableExpression?

Categories

Resources