Créer une clause where entièrement dynamique avec une arborescence d'expression et exécuter IQueryable

c# expression-trees iqueryable lambda where

Question

Au point (3) de mon code, j'ai défini une requête appelée requête1 dans laquelle j'ai défini une expression .Where lambda. Cette requête est en quelque sorte dynamique mais contient toujours des éléments statiques, elle fait toujours référence à Type Employee et à sa propriété (int) ClientID.

Maintenant, j'aime beaucoup faire la référence au type et à sa propriété dynamique, en fonction des paramètres de la méthode qui, par exemple, sont indiqués ci-dessous point (1).

Ce que j’ai essayé jusqu’à présent, c’est de dynamiser la partie statique de la requête définie au point (3) en la remplaçant par un arbre d’expression plus élaboré, comme indiqué dans (4), (5) et (6). Mais lorsque j'essaie de tout ajouter, il est dit que j'appelle .Where avec de mauvais paramètres. Je ne sais pas comment appeler .Where avec les bons paramètres afin de créer une sélection entièrement dynamique.

Est-ce que quelqu'un sait résoudre ce problème? J'ai passé une journée à chercher et je n'ai pas encore trouvé de solution.

        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;

Merci beaucoup d'avoir lu ma question! Si vous avez des questions à propos de ma question, n'hésitez pas à les poser :)

Réponse acceptée

C'est assez difficile à regarder de manière isolée, mais la première chose qui se passe est que Compile convient pas pour IQueryable - cela fonctionnera rarement (LINQ-to-Objects étant l'exception).

Un équivalent de WhereClause.Invoke(C.ClientID) consiste à utiliser Expression.Invoke pour appeler une sous-expression, mais même si elle est floue: LINQ-to-SQL le prendra en charge, EF peut-être "non", je n'ai pas vérifié à nouveau dans 4.0). En fin de compte, il serait plus robuste de créer lambda1 tant lambda1 Expression<Func<Employee,bool>> si possible:

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

Puis passez ceci à 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);



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi