Vamos começar devagar: IQueryable estende IEnumerable. O que isso significa?
Bem, o que quer que você queira fazer com IEnumerable, você também pode fazer com IQueryable.
Portanto, deve haver algumas diferenças conceituais entre os dois.
Pequeno aviso: quando falo de IEnumerable ou IQueryable, refiro-me à variação genérica.
Porém a maioria do que é dito aqui também se aplica à versão não genérica que foi usada antes do .NET 2.
Em primeiro lugar, podemos ver que ambos vivem em namespaces totalmente diferentes:
IEnumerable-System.Collections.GenericIQueryable-System.Linq
Então vemos que há uma grande diferença. IEnumerable é usado para coleções e IQueryable é usado para consultar dados.
Mas ambos têm um comportamento comum: elas iteram apenas “para frente” (forward collections).
É preciso materializá-los, por exemplo, via ToList().
IQueryable fornece principalmente duas novas propriedades:
IQueryProvider- Executa uma expressão contra outra coisa (por exemplo, LINQ to SQL - traduz a expressão para SQL válido)Expressão- Pode ser uma árvore de expressão inteira (por exemplo, predicados, seletores de valor, …)
Com esses dois conceitos, você pode construir todo um modelo complexo e traduzi-lo para a conexão subjacente (por exemplo, LINQ to XML / LINQ to SQL, …).
IEnumerable, simplificando, aceita apenas um delegate. Você pode ver isso muito claramente se, por exemplo, observar a definição de Where:
- A assinatura da versão
IEnumerableé:Where(Func<T, bool> predicate) - A assinatura da versão
IQueryableé:Where(Expression<Func<T, bool>> predicate)
O que acontece se usarmos IEnumerable para consultar dados no banco de dados
Considere o seguinte código:
IEnumerable<Funcionario> funcionarios = GetFuncionarios();
empregados.Where(e => e.Workload > 50).ToList();
E o mesmo exemplo, mas com um IQuerayable:
IQueryable<Funcionario> funcionarios = GetFuncionarios();
empregados.Where(e => e.Workload > 50).ToList();
Vamos supor que GetFuncionarios nos forneça um DbContext que desce para o SQL-Server.
No primeiro exemplo todos os Funcionarios são carregados para o cliente e depois o predicado é executado neles.
No segundo exemplo, todos os funcionários são filtrados no servidor e apenas os que atendem ao predicado são retornados ao cliente.
Se o seu conjunto de dados for grande o suficiente, isso fará uma grande diferença. Outro exemplo seria Paginação.
Skip e Take não funcionarão com IEnumerable em conexão com um banco de dados.
Você recuperaria todos os objetos na memória e executaria Skip e Take posteriormente (no cliente).
Resumo
Uma pequena visão geral:
- Ambos
IEnumerableeIQueryablesão coleções de encaminhamento - eles não são materializados imediatamente - Consultar dados do banco de dados
IEnumerablecarregará os dados na memória em um filtro posteriormente no cliente - A consulta de dados do banco de dados
IQueryableirá filtrar primeiro e depois enviar os dados filtrados para o cliente IQueryableé adequado para consultar dados de memória externa- Pode haver cenários em que o provedor de consulta subjacente não pode traduzir sua expressão para algo significativo, então você deve mudar para
IEnumerable