I am trying to build up an expression that will be applied to an IQueryable collection.
I can build an expression like this:
[TestClass]
public class ExpressionTests
{
private IQueryable<MyEntity> entities;
private class MyEntity
{
public string MyProperty { get; set; }
}
[TestInitialize]
public void Setup()
{
entities = new[]
{
new MyEntity {MyProperty = "first"},
new MyEntity {MyProperty = "second"}
}.AsQueryable();
}
[TestMethod]
public void TestQueryingUsingSingleExpression()
{
Expression<Func<MyEntity, bool>> expression = e => e.MyProperty.Contains("irs");
Assert.AreEqual(1, entities.Where(expression).Count());
}
}
Now I want to separate the two parts of the expression:
[TestMethod]
public void TestQueryingByCombiningTwoExpressions()
{
Expression<Func<MyEntity, string>> fieldExpression = e => e.MyProperty;
Expression<Func<string, bool>> operatorExpression = e => e.Contains("irs");
// combine the two expressions somehow...
Expression<Func<MyEntity, bool>> combinedExpression = ???;
Assert.AreEqual(1, entities.Where(combinedExpression).Count());
}
Any suggestions as to how I might do this?
Btw the provider that will be resolving the expression is Linq for NHibernate.
Take a look at your two expression trees:
| | Lambda Lambda / \ / \ / \ / \ Property Parameter x Call Parameter y / \ / | \ / \ / | \ x MyProperty EndsWidth y Constant | "5"
You need to create a new tree that looks like this:
| Lambda / \ / \ Call Parameter z / | \ / | \ EndsWith | Constant | \ Property "5" / \ / \ z MyProperty
You can easily see what parts of the new tree come from which original tree.
To create the tree, you take the body of the second lambda expression (Call) and replace all occurrences of y
with the body of the first lambda expression (Property) and all occurrences of x
with z
. Then you wrap the result in a new lambda expression with parameter z
.
You can use the ExpressionVisitor Class to rewrite the tree, and the Expression.Lambda Method to create the new lambda expression.
It depends on what the provider supports; if it supports sub-expressions (LINQ-to-SQL does, EF doesn't; I don't know about NH), then:
var combinedExpression = Expression.Lambda<Func<MyEntity, bool>>(
Expression.Invoke(operatorExpression, fieldExpression.Body),
fieldExpression.Parameters);
however, if it doesn't you'll need to use ExpressionVisitor
to merge them.
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