Erstellen Sie eine vollständig dynamische where-Klausel mit der Ausdrucksbaumstruktur und führen Sie sie auf IQueryable aus

c# expression-trees iqueryable lambda where

Frage

An Punkt (3) in meinem Code habe ich eine Abfrage namens query1 definiert, in der ich einen .Where Lambda-Ausdruck definiert habe. Diese Abfrage ist in gewisser Weise dynamisch, enthält aber immer noch statische Elemente. Sie bezieht sich immer auf den Type Employee und seine (int) Eigenschaft ClientID.

Nun möchte ich die Bezugnahme auf den Typ und seine Eigenschaft sehr dynamisch machen, basierend auf den Methodenparametern, die beispielhaft unter Punkt (1) gezeigt werden.

Was ich bis jetzt versucht habe, ist, den unter Punkt (3) definierten statischen Teil der Abfrage vollständig dynamisch zu machen, indem ich ihn durch einen ausgefeilteren Ausdrucksbaum, wie in (4), (5) und (6) beschrieben, ersetze. Aber wenn ich versuche, alles zusammen zu addieren, heißt es, ich rufe an. Wo mit falschen Parametern. Ich weiß nicht wie ich anrufen soll. Wo mit den richtigen Parametern um eine voll dynamische Auswahl zu erstellen.

Weiß jemand, um dieses Problem zu lösen? Ich habe einen Tag lang gesucht und bisher keine Lösung gefunden.

        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;

Vielen Dank für das Lesen meiner Frage! Wenn Sie Fragen zu meiner Frage haben, fragen Sie sie bitte :)

Akzeptierte Antwort

Das ist ziemlich schwer isoliert zu betrachten, aber das erste, was auftritt, ist, dass Compile für IQueryable fehl am Platz IQueryable - das wird selten funktionieren (LINQ to Objects ist die Ausnahme).

Ein Äquivalent zu WhereClause.Invoke(C.ClientID) ist es, mit Expression.Invoke einen Unterausdruck aufzurufen, aber auch das ist flakey: LINQ-to-SQL unterstützt es, EF (zumindest in 3.5) nicht ( vielleicht "nicht"; ich habe in 4.0 nicht nachgeprüft). Letztlich wäre es robuster, lambda1 als Expression<Func<Employee,bool>> wenn möglich zu erstellen:

    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);

Übergeben Sie das dann an Where :

    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);



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum