2010-06-01 11 views
54

J'avais besoin de construire un filtre dynamique et je voulais continuer à utiliser des entités. Pour cette raison, je voulais utiliser le PredicateBuilder d'albahari.C# Entités PredicateBuilder: Le paramètre 'f' n'était pas lié dans l'expression de requête LINQ to Entities spécifiée

J'ai créé le code suivant:

var invoerDatums = PredicateBuilder.True<OnderzoeksVragen>(); 
var inner = PredicateBuilder.False<OnderzoeksVragen>(); 

foreach (var filter in set.RapportInvoerFilter.ToList()) 
{ 
    if(filter.IsDate) 
    { 
     var date = DateTime.Parse(filter.Waarde); 
     invoerDatums = invoerDatums.Or(o => o.Van >= date && o.Tot <= date); 
    } 
    else 
    { 
     string temp = filter.Waarde; 
     inner = inner.Or(o => o.OnderzoekType == temp); 
    } 
} 

invoerDatums = invoerDatums.And(inner); 
var onderzoeksVragen = entities.OnderzoeksVragen 
           .AsExpandable() 
           .Where(invoerDatums) 
           .ToList(); 

Quand je courais le code il n'y avait que 1 filtre qui n'a pas un filtre de date. Donc, seul le prédicat interne a été rempli. Lorsque le prédicat a été exécuté, j'ai l'erreur suivante.

Le paramètre 'f' est pas lié dans la spécifiée LINQ aux entités requête expression .

Lors de la recherche d'une réponse, j'ai trouvé page. Mais ceci est déjà implémenté dans le LINQKit.

Est-ce que quelqu'un d'autre a rencontré cette erreur et sait comment la résoudre?

Répondre

121

Je couru à travers la même erreur, la question semblait être quand j'avais fait avec prédicats PredicateBuilder qui étaient à leur tour composé d'autres prédicats fabriqués avec PredicateBuilder

par exemple (A OU B) ET (X OU Y) où un constructeur crée A OU B, on crée X OU Y et un troisième ETs ensemble.

Avec un seul niveau de prédicats AsExpandable a bien fonctionné, quand plus d'un niveau a été introduit j'ai eu la même erreur.

Je n'ai pas été en mesure de trouver de l'aide, mais grâce à quelques essais et erreurs, j'ai pu faire bouger les choses. Chaque fois que j'ai appelé un prédicat, je l'ai suivi avec la méthode d'extension Expand.

est ici un peu de code, abattrez pour la simplicité:

public static IQueryable<Submission> AddOptionFilter(
    this IQueryable<Submission> query, 
    IEnumerable<IGrouping<int, int>> options) 
{ 
    var predicate = options.Aggregate(
     PredicateBuilder.False<Submission>(), 
     (accumulator, optionIds) => accumulator.Or(ConstructOptionMatchPredicate(optionIds).Expand())); 
     query = query.Where(predicate.Expand());    
    return query; 
} 

Query est un IQueryable qui a déjà eu AsExpandable appelé, ConstructOptionNotMatchPredicate retourne une expression. Une fois que nous avons dépassé l'erreur, nous avons certainement pu construire des filtres compliqués au moment de l'exécution par rapport à l'infrastructure de l'entité.

Edit:

Puisque les gens sont encore commentent et vote cette Je suppose qu'il est toujours utile, je partage donc une autre solution. Fondamentalement, j'ai arrêté d'utiliser LinqKit et son créateur de prédicat en faveur de ce Universal Predicate Builder qui a la même API, mais n'a pas besoin d'élargir les appels, il vaut la peine de vérifier.

+0

J'ai également dû supprimer l'appel à AsExpandable() de mon objet IQueryable d'origine. –

+2

Bonne réponse, mais trompeuse. La réponse de BloodBaz est la réponse la plus simple et la plus correcte – Mick

44

J'ai eu cette erreur et l'explication de Mant101 m'a obtenu la réponse, mais vous cherchez peut-être un exemple plus simple qui cause le problème:

// This predicate is the 1st predicate builder 
var predicate = PredicateBuilder.True<Widget>(); 

// and I am adding more predicates to it (all no problem here) 
predicate = predicate.And(c => c.ColumnA == 1); 
predicate = predicate.And(c => c.ColumnB > 32); 
predicate = predicate.And(c => c.ColumnC == 73); 

// Now I want to add another "AND" predicate which actually comprises 
// of a whole list of sub-"OR" predicates 
if(keywords.Length > 0) 
{ 
    // NOTICE: Here I am starting off a brand new 2nd predicate builder.... 
    // (I'm not "AND"ing it to the existing one (yet)) 
    var subpredicate = PredicateBuilder.False<Widget>(); 

    foreach(string s in keywords) 
    { 
     string t = s; // s is part of enumerable so need to make a copy of it 
     subpredicate = subpredicate.Or(c => c.Name.Contains(t)); 
    } 

    // This is the "gotcha" bit... ANDing the independent 
    // sub-predicate to the 1st one.... 

    // If done like this, you will FAIL! 
// predicate = predicate.And(subpredicate); // FAIL at runtime! 

    // To correct it, you must do this... 
    predicate = predicate.And(subpredicate.Expand()); // OK at runtime! 
} 

Hope this helps! :-)