Using the following example i would like to use my Expression inside my Contains method, having it pass the query onto sql server using the EF.
If I'm understanding correctly, what you want is expression composition:
public static IQueryable Filter(IQueryable query, Expression> getCompanyId) {
IEnumerable validCompanyIds = GetCompanyIdsFromDatabase();
Expression> filterByCompanyId = id => validCompanyIds.Contains(id);
// these generics will actually be inferred, I've just written them to be explicit
Expression> composed = filterByCompanyId.Compose(getCompanyId);
return query.Where(composed);
}
Below is the implementation of the Compose() extension method on expression:
///
/// Composes two lambda expressions f(y) and g(x), returning a new expression representing f(g(x)).
/// This is useful for constructing expressions to pass to functions like Where(). If given x => x.Id and id => ids.Contains(id),
/// for example, you can create the expression x => ids.Contains(x.Id), which could be passed to Where() for an IQueryable of x's type
///
/// The input of g
/// The output of g and the input of f
/// The output of f
/// The outer function
/// The inner function
/// A new lambda expression
public static Expression> Compose(this Expression> f, Expression> g)
{
// The implementation used here gets around EF's inability to process Invoke expressions. Rather than invoking f with the output of g, we
// effectively "inline" g by replacing all instances of f's parameter with g's body and creating a new lambda with the rebound body of f and
// the parameters of g
var map = f.Parameters.ToDictionary(p => p, p => g.Body);
var reboundBody = ParameterRebinder.ReplaceParameters(map, f.Body);
var lambda = Expression.Lambda>(reboundBody, g.Parameters);
return lambda;
}
public class ParameterRebinder : ExpressionVisitor
{
private readonly Dictionary Map;
public ParameterRebinder(Dictionary map)
{
this.Map = map ?? new Dictionary();
}
public static Expression ReplaceParameters(Dictionary map, Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression node)
{
Expression replacement;
if (this.Map.TryGetValue(node, out replacement))
{
return this.Visit(replacement);
}
return base.VisitParameter(node);
}
}