C# 使用表达式树创建完全动态的where子句,并在IQueryable上执行

C# 使用表达式树创建完全动态的where子句,并在IQueryable上执行,c#,lambda,expression-trees,iqueryable,where,C#,Lambda,Expression Trees,Iqueryable,Where,在代码的第(3)点,我定义了一个名为query1的查询,在其中我定义了一个.Where lambda表达式。这个查询在某种程度上是动态的,但仍然包含静态元素,它总是引用Employee类型及其(int)属性ClientID 现在,我非常喜欢根据下面第(1)点所示的方法参数,动态地引用类型及其属性 到目前为止,我试图将第(3)点下定义的查询的静态部分完全动态化,方法是将其替换为更复杂的表达式树,如第(4)、(5)和(6)点所述。但是当我试图把所有的东西都加在一起时,它说我调用了。在哪里使用了错误的

在代码的第(3)点,我定义了一个名为query1的查询,在其中我定义了一个.Where lambda表达式。这个查询在某种程度上是动态的,但仍然包含静态元素,它总是引用Employee类型及其(int)属性ClientID

现在,我非常喜欢根据下面第(1)点所示的方法参数,动态地引用类型及其属性

到目前为止,我试图将第(3)点下定义的查询的静态部分完全动态化,方法是将其替换为更复杂的表达式树,如第(4)、(5)和(6)点所述。但是当我试图把所有的东西都加在一起时,它说我调用了。在哪里使用了错误的参数。我不知道如何调用。在何处使用正确的参数以创建完全动态的选择

有人知道如何解决这个问题吗?我花了一天时间搜索,到目前为止还没有找到解决方案

        dsMain domainService = new dsMain();


        //(1)i want to rewrite the following four variables to method-parameters
        Type entityType = typeof(Employee);
        String targetProperty = "ClientID";
        Type entityProperty = typeof(Employee).GetProperty(targetProperty).PropertyType;
        int idToDelete = 5;


        //(2)create expression-function: idToDelete == entityType.targetProperty (in this case: Employee.ClientID)
        ParameterExpression numParam = Expression.Parameter(entityProperty, targetProperty.Substring(0, 3));
        ConstantExpression equalTarget = Expression.Constant(idToDelete, idToDelete.GetType());
        BinaryExpression intEqualsID = Expression.Equal(numParam, equalTarget);
        Expression<Func<int, bool>> lambda1 =
                    Expression.Lambda<Func<int, bool>>(
                    intEqualsID,
                    new ParameterExpression[] { numParam });

        //(3)I want to create query1 fully dynamic, so defining Employee or an other type and its property at run time
        WhereClause = lambda1.Compile();
        IQueryable<Employee> employees = domainService.GetEmployees();
        var query1 = employees.Where<Employee>(C => WhereClause.Invoke(C.ClientID)).Expression;



        //(4)create the operand body {value(ASP.test_aspx).WhereClause.Invoke(E.ClientID)}
        var operandbodyMethod = WhereClause.GetType().GetMethod("Invoke");
        var operandbodyType = typeof(System.Boolean);
        var operandbodyArgs1Expression = Expression.Parameter(entityType, entityType.Name.Substring(0, 1));
        var operandbodyArgs1 = Expression.MakeMemberAccess(operandbodyArgs1Expression, entityType.GetMember(targetProperty)[0]);
        var operandBodyObjectExp = Expression.Constant(this, this.GetType());
        var operandbodyObject = Expression.MakeMemberAccess(operandBodyObjectExp, this.GetType().GetMember("WhereClause")[0]);

        //(5)create the operand {E => value(ASP.test_aspx).WhereClause.Invoke(E.ClientID)}
        var operandbody = Expression.Call(operandbodyObject, operandbodyMethod, operandbodyArgs1);
        var operandParameter = Expression.Parameter(entityType, entityType.Name.Substring(0, 1));
        var operandType = typeof(Func<,>).MakeGenericType(entityType, typeof(System.Boolean));

        //(6)
        var operand = Expression.Lambda(operandType, operandbody, new ParameterExpression[] { operandParameter });
        var expressionType = typeof(Expression<>).MakeGenericType(operandType);
        var completeWhereExpression = Expression.MakeUnary(ExpressionType.Quote, operand, expressionType);


        //(7)the line below does not work
        var query2 = employees.Where<Employee>(completeWhereExpression).Expression;
dsMain域服务=新的dsMain();
//(1) 我想将以下四个变量重写为方法参数
类型entityType=typeof(员工);
字符串targetProperty=“ClientID”;
类型entityProperty=typeof(Employee).GetProperty(targetProperty).PropertyType;
int-idToDelete=5;
//(2) 创建表达式函数:idToDelete==entityType.targetProperty(在本例中为Employee.ClientID)
ParameterExpression numParam=Expression.Parameter(entityProperty,targetProperty.Substring(0,3));
ConstantExpression equalTarget=Expression.Constant(idToDelete,idToDelete.GetType());
BinaryExpression IntequalId=Expression.Equal(numParam,equalTarget);
表达式lambda1=
Lambda(
无能的,
新参数表达式[]{numParam});
//(3) 我想创建完全动态的query1,以便在运行时定义Employee或其他类型及其属性
WhereClause=lambda1.Compile();
IQueryable employees=domainService.GetEmployees();
var query1=employees.Where(C=>WhereClause.Invoke(C.ClientID)).Expression;
//(4) 创建操作数主体{value(ASP.test_aspx).WhereClause.Invoke(E.ClientID)}
var operanbodymethod=WhereClause.GetType().GetMethod(“调用”);
变量操作数bodyType=typeof(System.Boolean);
var operanbodyargs1expression=Expression.Parameter(entityType,entityType.Name.Substring(0,1));
var operanbodyargs1=Expression.MakeMemberAccess(operanbodyargs1expression,entityType.GetMember(targetProperty)[0]);
var operandomBodyObjectExp=Expression.Constant(this,this.GetType());
var operanbodyObject=Expression.MakeMemberAccess(operanbodyObjectExp,this.GetType().GetMember(“WhereClause”)[0]);
//(5) 创建操作数{E=>value(ASP.test\u aspx).WhereClause.Invoke(E.ClientID)}
var operanbody=Expression.Call(operanbodyobject、operanbodymethod、operanbodyargs1);
var operandom Parameter=Expression.Parameter(entityType,entityType.Name.Substring(0,1));
变量操作数类型=typeof(Func).MakeGenericType(entityType,typeof(System.Boolean));
//(6)
变量操作数=表达式.Lambda(操作数类型、操作数体、新参数表达式[]{operandomParameter});
var expressionType=typeof(表达式)。MakeGenericType(操作数类型);
var completeWhereExpression=Expression.MakeUnary(ExpressionType.Quote,操作数,ExpressionType);
//(7) 下面这行行不通
var query2=employees.Where(completeWhere表达式).Expression;
非常感谢您阅读我的问题!
如果您对我的问题有疑问,请询问他们:)

这很难孤立地看待,但首先发生的事情是,
Compile
看起来不适合
IQueryable
——这很少起作用(LINQ to对象是例外)

WhereClause.Invoke(C.ClientID)
相当的一种方法是使用
Expression.Invoke
调用子表达式,但即使这样也很简单:LINQ到SQL将支持它,EF(至少在3.5中)不支持(可能是“没有”;我还没有在4.0中重新检查)。最终,如果可能,将
lambda1
创建为
表达式将更加健壮:

    ParameterExpression empParam = Expression.Parameter(typeof(Employee),"emp");
    ConstantExpression equalTarget = Expression.Constant(idToDelete, idToDelete.GetType());
    BinaryExpression intEqualsID = Expression.Equal(
        Expression.PropertyOrField(empParam, targetProperty), equalTarget);
    Expression<Func<Exmployee, bool>> lambda1 =
                Expression.Lambda<Func<int, bool>>(
                intEqualsID,
                empParam);

无论您使用表达式树创建什么,您仍然需要一个IQueryable来操作。在您的示例中,什么是domainService?看起来像某种数据上下文,但不是LinqToSql。您有一个方法,GetEmployees(),domainService是否提供任何机制来获取基于System.Type的IQueryable,就像LinqToSql的方法一样?domainService扩展了LinqToEntitiesDomainService(),它是WCF RIA Services framework()的一部分。domainService为我的EDM中称为dbUbiHorecaEntities的每个实体都有特定的CRUD方法。它没有基于System.Type获取iQueryTables的特殊机制,但是,它可能与反射有关:每个实体X在domainService中都有一个名为getX()的get方法,返回一个iQueryTable。示例:IQueryable=domainService.GetType().GetMethod(“Get”+X.GetType().GetName()).Invoke(domainService,null)。这对你有帮助吗?谢谢你,马克!成功了!代码太少了。(顺便说一句,这在EF4.0中是可能的:)(也感谢柯克的努力:)
var query1 = employees.Where(lambda1);