我想动态生成一个linq.expressions.expression语句,我可以将其用作过滤器。
以下是我要转换为表达式的Linq查询示例:
ctx.customer.where(c=>ctx.Invoice.Any(i=>i.customerId == c.id));
这是我的尝试
using System.Linq.Expressions;
var c = Expression.parameter(typeof(Customer),"c");
var i = Expression.parameter(typeof(Invoice),"i");
var rightPart= Expression.Equal(
Expression.propertyorField(i,"customerId"), Expression.propertyorfield(c,"id")
请协助。
答案 0 :(得分:7)
当我需要手动创建linq表达式时,我只是让.Net为我创建来自lambda的表达式然后我可以探索它的结构。例如,在debug
下运行Expression<Func<TestObject, bool>> expression = t => t.Invoice.Any(i => i.CustomerId == t.Id);
并检查表达式变量。
答案 1 :(得分:5)
我认为LinqExpression
来自using LinqExpression = System.Linq.Expressions.Expression;
。
Any
没有特定的表达类型,因为它不是运算符等。 Any
是一个静态方法,因此您应该为此创建一个Call
表达式。
您需要基于静态方法语法而不是扩展方法语法来构建表达式:
ctx.customer.Where(c => Enumerable.Any(ctx.Invoice, i => i.customerId == c.id));
这有很多步骤。这是大纲,因为我没有时间正确地完成所有步骤。我不完全确定如何表示内部lambda中使用的c
参数不是该lambda的参数,而是外部lambda的参数。概括地说,你需要
Enumerable.Any
方法的正确重载。MakeGenericMethod
)。ctx.Invoce
)rightPart
)。var innerLambda = Expression.Lambda(rightPart, i);
)Where
的LambdaExpression(即Expression.Lambda(methodCallExpression, c)
。如果您想要结合评论中指明的布尔表达式,第四步将会有所不同。
我希望有所帮助。
答案 2 :(得分:2)
请注意,我添加了内部表达式。你需要做一些关闭代码,因为你有一个捕获的变量。
请注意使用https://stackoverflow.com/a/3472250/90475中的代码时的简化机会。
在DebugView中获取表达式代码的最小代码...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace ConsoleApplication7
{
class CTX
{
public List<Customer> Invoices = new List<Customer>();
}
class Customer
{
public int id;
public static bool HasMatchingIds(Customer first, Customer second) { return true; }
}
class Program
{
static void Main(string[] args)
{
CTX ctx = new CTX();
Expression<Func<Customer, bool>> expression = cust => ctx.Invoices.Any(customer => Customer.HasMatchingIds(customer, cust));
}
}
}
这是我在反射器中看到的内容:
private static void Main(string[] args)
{
ParameterExpression CS$0$0000;
ParameterExpression CS$0$0002;
CTX ctx = new CTX();
Expression<Func<Customer, bool>> expression = Expression.Lambda<Func<Customer, bool>>(
Expression.Call(null, (MethodInfo) methodof(Enumerable.Any),
new Expression[] { Expression.Constant(ctx.Invoices), Expression.Lambda<Func<Customer, bool>>(
Expression.Call(null, (MethodInfo) methodof(Customer.HasMatchingIds), new Expression[] {
CS$0$0002 = Expression.Parameter(typeof(Customer), "customer"),
CS$0$0000 = Expression.Parameter(typeof(Customer), "cust") }),
new ParameterExpression[] { CS$0$0002 }) }), new ParameterExpression[] { CS$0$0000 });
}
足够接近政府工作......这告诉我,这远非微不足道,您需要简化原始查询。
我也会尝试运行LinqPad进行快速原型设计
答案 3 :(得分:1)
添加此代码:
var any = Expression.Call(typeof(Queryable), "Any", new Type[] { typeof(Invoice) },
Expression.PropertyOrField(Expression.Constant(ctx), "Invoice"),
Expression.Lambda(rightPart, i));
var filter = Expression.Lambda<Func<Customer, bool>>(any, c);
然后,您可以在filter
方法中使用IQueryable<Customer>.Where
作为参数。