Comment obtenir un prédicat dynamique en utilisant des expressions lors de la jointure dans Linq

c# expression-trees lambda linq linq-to-entities

Question

J'ai écrit une méthode statique qui donnera le prédicat approprié lambda en utilisant expression api pour différents types de champs.

static Func<T, bool> Process<T>(string type)
{

    ParameterExpression parameter = Expression.Parameter(typeof(T));
    Expression predicate = Expression.Constant(true);
    if (type == "Start")
    {
        Expression prop = Expression.Property(parameter, type);
        Expression filter = Expression.LessThan(prop, Expression.Constant(DateTime.Now));
        predicate = Expression.AndAlso(predicate, filter);
    }
    //TODO: more if statments to come
    var lambda = Expression.Lambda<Func<T, bool>>(predicate, parameter);
    return lambda.Compile();
}

Le code ci-dessus fonctionne bien si je fais une seule requête dans linq comme ceci:

var del = Process<MyClass>("Start");
var data = DbContext.MyClass.Where(del); //gets the result data

public class MyClass
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    public long Id { get; set; }
}

Maintenant, si je fais une jointure sur l'entité MyClass

var data = DbContext.MyClass
         .Join(DbContext.Detail, mc => mc.Id, detail => detail.Id, (m, d) =>
                     new { m = m, d = d})
         .Where(del);

Les lignes ci-dessus donnent une erreur de compilation

Error   CS1929  'IQueryable<<anonymous type: MyClass m, Detail d>>' does not contain a definition for 'Where' and the best extension method overload 'EnumerableRowCollectionExtensions.Where<MyClass>(EnumerableRowCollection<MyClass>, Func<MyClass, bool>)' requires a receiver of type 'EnumerableRowCollection<MyClass>'

Je comprends que .Where() attend maintenant un type anonyme qui a m et d mais pas sûr de savoir comment résoudre cela.

Je suis assez nouveau dans l'API Expression. Je ne sais pas comment y parvenir.

J'ai essayé d'y parvenir en créant une variable de type anonyme, mais il s'agit d'une variable et non du type lui-même pour la transmettre à Process<T>() .

Réponse acceptée

Le résultat de votre méthode Process est une clause Where pour les objets de type MyClass . Vous ne pouvez donc pas l'utiliser pour filtrer des objets anonymes { m, d } . Filtrez plutôt avant la Join :

var data = DbContext.MyClass.Where(del);                        
                            .Join(DbContext.Detail,
                                  mc => mc.Id,
                                  detail => detail.Id,
                                  (m, d) => new { m, d }
                             );


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