2016-07-28 2 views
-3

Supposons que j'ai une table jointe à 2 dans une fonction qui renvoie un IQueryable, mais la sortie est un type nommé qui n'est ni l'un ni l'autre tables:Pouvez-vous ajouter un Where() à un IQueryable lorsque le champ n'est pas dans la sortie sélectionnée?

var qry = from p in Persons 
      join h in Hobbies on p.PersonId equals h.PersonId 
      select new OutputType 
      { 
       Name = p.FirstName, 
       Hobby = h.HobbyName 
      } 

return qry 

Disons que maintenant, je voulais prendre ce retour requête et faire quelque chose comme:

var newQuery = qry.Where(p=>p.Age > 18) 

comme vous pouvez le voir c'est un problème parce que le IQueryable est de type OutputType, donc je peux N'ajouter un où à l'âge d'une personne à moins que je devais ajouter l'âge à OutputType. Y a-t-il un moyen de 'pénétrer' dans l'arbre d'expression de IQueryable et d'ajouter un lambda qui va interroger la collection source spécifiée et lui ajouter une clause Where? Ou dois-je dois-je ajouter un champ Where au OutputType même si je ne suis pas intéressé à le projeter en fin de compte?

+3

Bien que je pense que vous pourriez trouver un moyen de le faire si vous vouliez vraiment, vraiment il est juste un signe que votre conception est erronée, et vous devez structurer votre code tel que vous faites le filtrage avant projeter la séquence. – Servy

+0

Peut-être que vous pourriez reconcevoir un peu et transmettre la valeur de 'Persons'. Donc, à la place de 'Persons' vous passeriez dans' Persons.Where (p => p.Age> 18) ' –

+0

L'exemple que j'ai donné était juste cela, un exemple. Je montrais juste le concept, pas l'utilisation. Le cas réel est une jointure à 4 tables au-dessus d'une base de données Oracle héritée existante. J'ai 3 variations différentes de la même requête (grande), ne différant que par la clause Where sur les valeurs non-projetées des différentes tables. J'essaye de réduire la redondance dans le code ainsi je ne maintiens pas plusieurs grandes requêtes LINQ. La première réponse ci-dessous est très utile car je ne suis pas pénalisé pour avoir ajouté un champ dès le début et ne pas le projeter en fin de compte. Le seul point négatif est d'avoir à faire plusieurs nouveaux types. –

Répondre

1

Il est plus facile d'affiner votre vue plus tard que d'essayer de revenir en arrière. Voici un exemple dépouillé de comment j'aime calques de méthodes pour la réutilisation afin qu'elles crachent le sql gentil. Linq-to-entity ne vous pénalise pas d'avoir sélectionné la colonne supplémentaire de façon anticipée. Comme vous pouvez le voir, le sql inclut la colonne Coût dans la contrainte mais pas dans la sélection.

SELECT 
    1 AS [C1], 
    [Extent1].[ComponentNumber] AS [ComponentNumber], 
    [Extent1].[ComponentDescription] AS [ComponentDescription], 
    [Extent1].[ComponentPrice] AS [ComponentPrice] 
FROM [dbo].[Component] AS [Extent1] 
WHERE [Extent1].[ComponentCost] < @p__linq__0 
+0

Le seul point négatif est la création de tous ces types nommés pour chaque couche, mais la réponse que vous avez donnée est très solide. Il est en effet dommage que les bits de l'IQueryable soient si difficiles d'accès sur un retour de méthode, mais je me doutais que ce serait le cas. Merci! –