Utiliser IQueryable avec Linq
  à quoi sert  IQueryable  dans le contexte de LINQ?  
est-il utilisé pour mettre au point des méthodes d'extension ou à toute autre fin?
4 réponses
la réponse de Marc Gravell est très complète, mais j'ai pensé que je voudrais ajouter quelque chose à ce sujet du point de vue de l'utilisateur, ainsi...
  la principale différence, du point de vue de l'utilisateur, est que, lorsque vous utilisez  IQueryable<T>  (avec un fournisseur qui supporte les choses correctement), vous pouvez économiser beaucoup de ressources.  
  par exemple, si vous travaillez contre une base de données distante, avec de nombreux systèmes ORM, vous avez la possibilité de récupérer des données à partir d'une table de deux façons, l'une qui retourne  IEnumerable<T>  , et l'autre qui retourne un  IQueryable<T>  .  Par exemple, vous avez une table de produits, et vous voulez obtenir tous les produits dont le coût est >$25.  
si vous le faites:
 IEnumerable<Product> products = myORM.GetProducts();
 var productsOver25 = products.Where(p => p.Cost >= 25.00);
  ce qui se passe ici, est la base de données charge tous les produits, et les passe à travers le fil à votre programme.  Votre programme filtre ensuite les données.  Essentiellement, la base de données fait un  SELECT * FROM Products , et vous renvoie chaque produit.  
  avec le droit  IQueryable<T>  fournisseur, d'autre part, vous pouvez faire:  
 IQueryable<Product> products = myORM.GetQueryableProducts();
 var productsOver25 = products.Where(p => p.Cost >= 25.00);
 le code ressemble au même, mais la différence ici est que le SQL exécuté sera SELECT * FROM Products WHERE Cost >= 25 .  
de votre POV en tant que développeur, cela ressemble à la même chose. Cependant, du point de vue de la performance, vous ne pouvez retourner que 2 enregistrements sur le réseau au lieu de 20 000....
 en substance, son travail est très similaire à IEnumerable<T> - pour représenter une source de données interrogeable - la différence étant que les différentes méthodes LINQ (sur Queryable ) peut être plus spécifique, pour construire la requête en utilisant Expression arbres plutôt que délégués (ce qui est ce que Enumerable  utilise).  
les arbres d'expression peuvent être inspectés par votre fournisseur de LINQ choisi et transformés en une requête réelle - bien que ce soit un art noir dans m'.
 c'est en fait le ElementType , Expression et Provider - mais en réalité vous  rarement  besoin de se soucier de cela comme un  utilisateur  . Seul un LINQ    implémenter    a besoin de connaître les détails sanglants.  
  Re des commentaires; je ne suis pas tout à fait sûr de ce que vous voulez, par exemple, mais envisager de LINQ-to-SQL; l'objet central ici est un   DataContext , qui représente l'enveloppe de notre base de données. Il possède généralement une propriété par table (par exemple,  Customers  ), et une table implémente  IQueryable<Customer>  . Mais nous n'utilisons pas tant que cela directement; considérons:  
using(var ctx = new MyDataContext()) {
    var qry = from cust in ctx.Customers
              where cust.Region == "North"
              select new { cust.Id, cust.Name };
    foreach(var row in qry) {
        Console.WriteLine("{0}: {1}", row.Id, row.Name);
    }
}
cela devient (par le compilateur C#):
var qry = ctx.Customers.Where(cust => cust.Region == "North")
                .Select(cust => new { cust.Id, cust.Name });
qui est de nouveau interprété (par le compilateur C#) comme:
var qry = Queryable.Select(
              Queryable.Where(
                  ctx.Customers,
                  cust => cust.Region == "North"),
              cust => new { cust.Id, cust.Name });
  fait important, les méthodes statiques sur  Queryable  prennent expression les arbres , qui-plutôt que IL régulier, obtenir compilé à un modèle d'objet. Par exemple-en regardant juste le "où", cela nous donne quelque chose comparable à:  
var cust = Expression.Parameter(typeof(Customer), "cust");
var lambda = Expression.Lambda<Func<Customer,bool>>(
                  Expression.Equal(
                      Expression.Property(cust, "Region"),
                      Expression.Constant("North")
                  ), cust);
... Queryable.Where(ctx.Customers, lambda) ...
le compilateur n'a-t-il pas fait beaucoup pour nous? Ce modèle d'objet peut être déchiré, inspecté pour ce qu'il signifie, et assemblé à nouveau par le générateur TSQL-donnant quelque chose comme:
 SELECT c.Id, c.Name
 FROM [dbo].[Customer] c
 WHERE c.Region = 'North'
(la chaîne pourrait finir comme un paramètre; je ne me souviens pas)
  rien de tout cela ne serait possible si nous avions eu recours à un délégué. Et   ce  est le point de Queryable  /  IQueryable<T> : il fournit le point d'entrée pour l'utilisation des arbres d'expression.  
Tout cela est très complexe, donc c'est un bon travail que le compilateur rend agréable et facile pour nous.
pour plus d'information, regardez " C# en profondeur " ou " LINQ en Action ", tous les deux qui fournissent la couverture de ces sujets.
  bien que    Reed Copsey    et    Marc Gravell    déjà décrit sur  IQueryable  (et aussi  IEnumerable ) assez, mI veulent ajouter un peu plus ici en fournissant un petit exemple sur  IQueryable  et  IEnumerable  comme de nombreux utilisateurs l'ont demandé  
exemple : j'ai créé deux tableaux dans la base de données
   CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Gender] [nchar](1) NOT NULL)
   CREATE TABLE [dbo].[Person]([PersonId] [int] NOT NULL PRIMARY KEY,[FirstName] [nvarchar](50) NOT NULL,[LastName] [nvarchar](50) NOT NULL)
  la clef primaire ( PersonId ) du tableau   Employee  est également une fausse clé ( personid ) du tableau  Person   
ensuite j'ai ajouté ado.net modèle d'entité dans mon application et créer en dessous de la classe de service sur cela
public class SomeServiceClass
{   
    public IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable(IEnumerable<int> employeesToCollect)
    {
        DemoIQueryableEntities db = new DemoIQueryableEntities();
        var allDetails = from Employee e in db.Employees
                         join Person p in db.People on e.PersonId equals p.PersonId
                         where employeesToCollect.Contains(e.PersonId)
                         select e;
        return allDetails;
    }
    public IEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable(IEnumerable<int> employeesToCollect)
    {
        DemoIQueryableEntities db = new DemoIQueryableEntities();
        var allDetails = from Employee e in db.Employees
                         join Person p in db.People on e.PersonId equals p.PersonId
                         where employeesToCollect.Contains(e.PersonId)
                         select e;
        return allDetails;
    }
}
  ils contiennent même linq. Il a appelé dans  program.cs  comme défini ci-dessous  
class Program
{
    static void Main(string[] args)
    {
        SomeServiceClass s= new SomeServiceClass(); 
        var employeesToCollect= new []{0,1,2,3};
        //IQueryable execution part
        var IQueryableList = s.GetEmployeeAndPersonDetailIQueryable(employeesToCollect).Where(i => i.Gender=="M");            
        foreach (var emp in IQueryableList)
        {
            System.Console.WriteLine("ID:{0}, EName:{1},Gender:{2}", emp.PersonId, emp.Person.FirstName, emp.Gender);
        }
        System.Console.WriteLine("IQueryable contain {0} row in result set", IQueryableList.Count());
        //IEnumerable execution part
        var IEnumerableList = s.GetEmployeeAndPersonDetailIEnumerable(employeesToCollect).Where(i => i.Gender == "M");
        foreach (var emp in IEnumerableList)
        {
           System.Console.WriteLine("ID:{0}, EName:{1},Gender:{2}", emp.PersonId, emp.Person.FirstName, emp.Gender);
        }
        System.Console.WriteLine("IEnumerable contain {0} row in result set", IEnumerableList.Count());
        Console.ReadKey();
    }
}
la sortie est la même pour les deux évidemment
ID:1, EName:Ken,Gender:M  
ID:3, EName:Roberto,Gender:M  
IQueryable contain 2 row in result set  
ID:1, EName:Ken,Gender:M  
ID:3, EName:Roberto,Gender:M  
IEnumerable contain 2 row in result set
la question est donc quelle est/Quelle est la différence? Il n'a pas semblent toute différence de droite? Vraiment!!
regardons les requêtes sql générées et exécutées par entity framwork 5 pendant cette période
IQueryable l'exécution de la partie
--IQueryableQuery1 
SELECT 
[Extent1].[PersonId] AS [PersonId], 
[Extent1].[Gender] AS [Gender]
FROM [dbo].[Employee] AS [Extent1]
WHERE ([Extent1].[PersonId] IN (0,1,2,3)) AND (N'M' = [Extent1].[Gender])
--IQueryableQuery2
SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    COUNT(1) AS [A1]
    FROM [dbo].[Employee] AS [Extent1]
    WHERE ([Extent1].[PersonId] IN (0,1,2,3)) AND (N'M' = [Extent1].[Gender])
)  AS [GroupBy1]
IEnumerable l'exécution de la partie
--IEnumerableQuery1
SELECT 
[Extent1].[PersonId] AS [PersonId], 
[Extent1].[Gender] AS [Gender]
FROM [dbo].[Employee] AS [Extent1]
WHERE [Extent1].[PersonId] IN (0,1,2,3)
--IEnumerableQuery2
SELECT 
[Extent1].[PersonId] AS [PersonId], 
[Extent1].[Gender] AS [Gender]
FROM [dbo].[Employee] AS [Extent1]
WHERE [Extent1].[PersonId] IN (0,1,2,3)
script Commun pour l'exécution de la partie
/* these two query will execute for both IQueryable or IEnumerable to get details from Person table
   Ignore these two queries here because it has nothing to do with IQueryable vs IEnumerable
--ICommonQuery1 
exec sp_executesql N'SELECT 
[Extent1].[PersonId] AS [PersonId], 
[Extent1].[FirstName] AS [FirstName], 
[Extent1].[LastName] AS [LastName]
FROM [dbo].[Person] AS [Extent1]
WHERE [Extent1].[PersonId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1
--ICommonQuery2
exec sp_executesql N'SELECT 
[Extent1].[PersonId] AS [PersonId], 
[Extent1].[FirstName] AS [FirstName], 
[Extent1].[LastName] AS [LastName]
FROM [dbo].[Person] AS [Extent1]
WHERE [Extent1].[PersonId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=3
*/
donc vous avez peu de questions maintenant, laissez-moi deviner ceux-ci et essayer de répondre à eux
pourquoi des scripts différents sont-ils générés pour le même résultat?
voyons quelques points ici,
toutes les requêtes ont une partie commune
  WHERE [Extent1].[PersonId] IN (0,1,2,3)   
  pourquoi? Parce que les deux fonctions  IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable  et 
  IEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable  de   SomeServiceClass  contient une ligne commune dans les requêtes linq  
   where employeesToCollect.Contains(e.PersonId)   
  que Pourquoi est le
 La partie AND (N'M' = [Extent1].[Gender]) est manquante dans la partie IEnumerable d'exécution, alors que dans les deux cas nous avons utilisé le programme Where(i => i.Gender == "M") in .cs ' 
maintenant nous sommes au point où la différence est venue entre
IQueryableetIEnumerable
  Ce entity framwork n'quand un  IQueryable   méthode appelée, elle fait tourner l'instruction linq écrite à l'intérieur de la méthode et essaye de savoir si plus d'expressions linq sont définies sur le jeu de résultats, elle rassemble alors toutes les requêtes linq définies jusqu'à ce que le résultat ait besoin de fetch et construit une requête sql plus appropriée à exécuter.   
Il fournir beaucoup d'avantages comme,
- exécution des requêtes linq whole
- aide les performances du serveur sql en ne sélectionnant pas les lignes inutiles
- réduction des coûts de réseau
comme ici dans l'exemple sql server retourné à l'application seulement deux lignes après l'exécution IQueryable 'mais retourné trois lignes pour IEnumerable question pourquoi?
  dans le cas de la méthode  IEnumerable , entity framework a pris la déclaration linq écrite à l'intérieur de la méthode et construit la requête sql quand résultat besoin de récupérer. il n'inclut pas la partie rest linq pour construire la requête sql. Comme ici aucun filtrage n'est fait dans sql server sur la colonne  gender  .   
Mais les sorties sont les mêmes? Parce que 'filtres IEnumerable le résultat plus loin dans le niveau d'application après avoir récupéré le résultat du serveur sql
    ,    que doit-on choisir?
Personnellement, je préfère définir fonction résultat comme  IQueryable<T>  parce qu'Il ya beaucoup de l'avantage, il a plus de  IEnumerable  comme, vous pourriez rejoindre deux ou plusieurs fonctions IQueryable, qui génèrent script plus spécifique à sql server.  
 ici dans l'exemple vous pouvez voir un IQueryable Query(IQueryableQuery2) génère un script plus spécifique que IEnumerable query(IEnumerableQuery2)  qui est beaucoup plus acceptable à mon point de vue.  
il permet d'interroger plus loin sur la ligne. Si cela était au-delà d'une limite de service, par exemple, alors l'utilisateur de cet objet IQueryable serait autorisé à en faire plus avec lui.
par exemple, si vous utilisiez le chargement paresseux avec nhibernate, cela pourrait conduire à charger graph quand/si nécessaire.