Filtre Entity Framework “Expression <Func >”

J’essaie de créer une méthode de filtrage pour la structure Entity Listez et comprenez mieux l’ Expression<Func<...

J’ai une fonction de test comme celle-ci.

 public IQueryable Filter(IEnumerable src, Expression<Func> pred) { return src.AsQueryable().Where(pred); } 

et si je fais ceci:

 context.Table.Filter(e => e.ID < 500); 

ou ca:

 context.Table.Filter(e => e.SubTable.Where(et => et.ID  0 && e.ID < 500); 

tout fonctionne bien.

Mais si je fais ça:

 context.Table.Filter(e => e.SubTable.Filter(et => et.ID  0 && e.ID < 500); 

ou ca:

 context.Table.Where(e => e.SubTable.Filter(et => et.ID  0 && e.ID < 500); 

Je reçois une erreur. LINQ to Entities does not recognize the method ...Filter...

Pourquoi cela fonctionne-t-il dans un cas et non dans l’additionneur? Que dois-je changer dans le filtre pour que cela fonctionne avec les tables associées? Je préfère restr à l’écart des autres bibliothèques externes, car ce que je veux, c’est apprendre à l’utiliser et pouvoir l’utiliser dans n’importe quel scénario à l’avenir.

Dans les deux premiers cas, le filtre s’exécute correctement dans la firebase database.

Jon et Tim ont déjà expliqué pourquoi cela ne fonctionne pas.

En supposant que le code de filtre dans Filter ne soit pas sortingvial, vous pouvez modifier le Filter afin qu’il retourne une expression qu’ EF peut traduire.

Supposons que vous avez ce code:

 context.Table.Where(x => x.Name.Length > 500); 

Vous pouvez maintenant créer une méthode qui retourne cette expression:

 Expression> FilterByNameLength(int length) { return x => x.Name.Length > length; } 

L’utilisation serait comme ceci:

 context.Table.Where(FilterByNameLength(500)); 

L’expression que vous FilterByNameLength dans FilterByNameLength peut être arbitrairement complexe, à condition de pouvoir la transmettre directement à Where .

Il est utile de comprendre la différence entre Expression> et Func<> .

Une Expression e => e.ID < 500 enregistre les informations relatives à cette expression: il y a un T e , vous accédez à l' ID propriété en appelant l'opérateur < avec la valeur int 500 . Lorsque EF regarde cela, il peut le transformer en quelque chose comme [SomeTable].[ID] < 500 .

Un Func e => e.ID < 500 est une méthode équivalente à:

 static bool MyMethod(T e) { return e.ID < 500; } 

Il est compilé en tant que code IL qui le fait; il n'est pas conçu pour être «reconstitué» dans une requête SQL ou autre chose, seulement exécuté.

Lorsque EF prend votre Expression , il doit comprendre chaque élément de celle-ci, car il l'utilise pour créer une requête SQL. Il est programmé pour savoir ce que signifie la méthode Where existante. Il ne sait pas ce que votre méthode de Filter signifie, même si c'est une méthode sortingviale, alors elle abandonne tout simplement.

Pourquoi cela fonctionne-t-il dans un cas et non dans l’additionneur?

Parce qu’EF ne “connait” pas vraiment votre méthode de Filter . Il ne comprend pas ce qu’il est censé faire et ne sait donc pas le traduire en SQL. Comparez cela avec Where , ce qu’il comprend.

La version où vous l’appelez directement sur la table initiale fonctionne car vous évitez ainsi d’avoir une arborescence d’expression contenant un appel à Filter – elle appelle simplement Filter , ce qui génère une requête … mais une seule ce que EF comprend.

Je serais très surpris si vous pouviez trouver un moyen de faire en sorte que votre méthode Filter fonctionne dans une requête EF … mais vous avez déjà dit que l’utilisation de Where fonctionne quand même, alors pourquoi utiliser Filter du tout? J’utiliserais la version Where – ou mieux encore, utiliserait Any surcharge qui prend un prédicat:

 context.Table.Filter(e => e.SubTable.Any(et => et.ID < 500) && e.ID < 500);