Qual é a diferença entre IQueryable <T> e IEnumerable <T>?


Respostas:


258

Primeiro de tudo, estende a interface, então qualquer coisa que você possa fazer com um "simples" , você também pode fazer com um .IQueryable<T> IEnumerable<T>IEnumerable<T>IQueryable<T>

IEnumerable<T>só tem um GetEnumerator()método que retorna um Enumerator<T>para o qual você pode chamar seu MoveNext()método para percorrer uma sequência de T .

O IQueryable<T>que tem isso IEnumerable<T> não são duas propriedades em particular - uma que aponta para um provedor de consulta (por exemplo, um provedor LINQ to SQL) e outra que aponta para uma expressão de consulta que representa o IQueryable<T>objeto como uma árvore de sintaxe abstrata que pode ser percorrida em tempo de execução e que pode ser entendido pelo provedor de consulta fornecido (na maioria das vezes, você não pode atribuir uma expressão LINQ to SQL a um provedor LINQ to Entities sem que uma exceção seja lançada).

A expressão pode simplesmente ser uma expressão constante do próprio objeto ou uma árvore mais complexa de um conjunto composto de operadores e operandos de consulta. Os métodos IQueryProvider.Execute()ou provedor de consulta IQueryProvider.CreateQuery()são chamados com uma expressão passada para ele e, em seguida, um resultado da consulta ou outro IQueryableé retornado, respectivamente.


8
Existe algum benefício em usar o AsQueryable?
Jordânia

6
O único benefício é a conveniência. AsQueryable()apenas converterá um enumerável em um questionável e o retornará se implementar a IQueryableinterface; caso contrário, ele o envolverá em um ConstantExpression, que é referido em um EnumerableQueryobjeto retornado .
Mark Cidade


1
Vale a pena ler este artigo
JenonD 30/10

O link @JenonD está morto, aqui está o waybackmachine: web.archive.org/web/20160904162931/http://www.dotnet-tricks.com/…
majjam

201

A principal diferença é que os operadores LINQ IQueryable<T>recebem Expressionobjetos em vez de delegados, o que significa que a lógica de consulta personalizada que recebe, por exemplo, um predicado ou seletor de valor, está na forma de uma árvore de expressão em vez de um delegado em um método.

  • IEnumerable<T> é ótimo para trabalhar com sequências iteradas na memória, mas
  • IQueryable<T> permite a falta de memória, como uma fonte de dados remota, como um banco de dados ou serviço da web.

Execução de consulta:

  • Onde a execução de uma consulta será executada "em processo" , normalmente tudo o que é necessário é o código (como código) para executar cada parte da consulta.

  • Onde a execução será executada fora do processo , a lógica da consulta deve ser representada nos dados, para que o provedor LINQ possa convertê-la no formato apropriado para a execução de falta de memória - seja uma consulta LDAP, SQL ou o que seja.

Mais em:

http://www.codeproject.com/KB/cs/646361/WhatHowWhere.jpg


14
Eu gosto da menção de operações de falta de memória. Esclarece uma diferença prática real no uso.
Ishmael Smyrnow

2
Em vez de usar delegados como parâmetros, como o método IEnumerable <T> Where, o IQueryable <T> aceita os parâmetros Expression <TDelegate>. Não estamos passando código para IQueryable <T>, estamos passando árvores de expressão (código como dados) para o provedor LINQ analisar. C # 3.0 e LINQ
Lu55

algo está acontecendo com a sua imagem link, a sua não prestação no corpo pós por algum motivo codeproject.com/KB/cs/646361/WhatHowWhere.jpg
jbooker

@joey No entanto, vejo que a imagem muito bem nesta resposta: i.stack.imgur.com/2DAqv.jpg
VonC

190

Este é um belo vídeo no youtube que demonstra como essas interfaces diferem, vale a pena assistir.

Abaixo segue uma longa resposta descritiva para ele.

O primeiro ponto importante a ser lembrado é a IQueryableinterface herdada de IEnumerable, portanto, o que quer que IEnumerablepossa fazer, IQueryabletambém pode fazer.

insira a descrição da imagem aqui

Existem muitas diferenças, mas vamos discutir sobre a grande diferença que faz a maior diferença. IEnumerableA interface é útil quando sua coleção é carregada usando a LINQestrutura Entity e você deseja aplicar um filtro à coleção.

Considere o código simples abaixo que usa IEnumerablecom a estrutura da entidade. Está usando um Wherefiltro para obter registros de quem EmpIdé 2.

EmpEntities ent = new EmpEntities();
IEnumerable<Employee> emp = ent.Employees; 
IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();

É onde o filtro é executado no lado do cliente onde está o IEnumerablecódigo. Em outras palavras, todos os dados são buscados no banco de dados e, em seguida, no cliente, as varreduras e o registro EmpIdsão 2.

insira a descrição da imagem aqui

Mas agora veja o código abaixo mudamos IEnumerablepara IQueryable. Ele cria uma Consulta SQL no lado do servidor e apenas os dados necessários são enviados para o lado do cliente.

EmpEntities ent = new EmpEntities();
IQueryable<Employee> emp = ent.Employees;
IQueryable<Employee> temp =  emp.Where(x => x.Empid == 2).ToList<Employee>();

insira a descrição da imagem aqui

Portanto, a diferença entre IQueryablee IEnumerableé sobre onde a lógica do filtro é executada. Um é executado no lado do cliente e o outro no banco de dados.

Portanto, se você trabalha apenas com a coleta de dados na memória IEnumerableé uma boa opção, mas se deseja consultar a coleta de dados conectada ao banco de dados, o IQueryable é uma escolha melhor, pois reduz o tráfego na rede e usa o poder da linguagem SQL.


Oi, muito obrigado pela explicação maravilhosa. Entendo por que o IQueryable é a melhor opção para dados "sem memória", mas estou tentando entender por que o IEnumerable é melhor para os dados "in-memory"? Ainda acho que é melhor obter dados filtrados do que obter dados e aplicar filtro.
Imad

quando está "na memória", isso realmente não importa. os dados já estão na memória, a que horas são filtrados, não importa.
Roni Axelrad

@Imad Por exemplo, projetar dados convertendo a entidade DateTimeOffset em DateTime não pode ser possível usando IQueryable ou EntityFunctions. A melhor maneira é AsEnumerable () o objeto da entidade e, em seguida, Select () em um viewmodel que contém o DateTime. Este processo usa funções na memória.
Jeff

57

IEnumerable: IEnumerable é mais adequado para trabalhar com coleção na memória (ou consultas locais). IEnumerable não se move entre itens, é encaminhar apenas a coleção.

IQueryable: o IQueryable é mais adequado para fontes de dados remotas, como um banco de dados ou serviço da Web (ou consultas remotas). O IQueryable é um recurso muito poderoso que permite uma variedade de cenários interessantes de execução adiada (como consultas baseadas em paginação e composição).

Portanto, quando você precisar simplesmente percorrer a coleção na memória, use IEnumerable; se precisar manipular a coleção como Dataset e outras fontes de dados, use IQueryable


3
IEnumerable não usa execução adiada?
precisa

3
A execução adiada está disponível no IEnumerable e no IQueryable. Mais informações interessantes podem ser encontradas aqui: stackoverflow.com/questions/2876616/…
Ignacio Hagopian

18

Em outras palavras, outra grande diferença é que o IEnumerable executa a consulta de seleção no lado do servidor, carrega dados na memória no lado do cliente e filtra os dados enquanto o IQueryable executa a consulta de seleção no lado do servidor com todos os filtros.


17

Na vida real, se você estiver usando um ORM como LINQ-to-SQL

  • Se você criar um IQueryable, a consulta poderá ser convertida em sql e executada no servidor de banco de dados
  • Se você criar um IEnumerable, todas as linhas serão puxadas para a memória como objetos antes de executar a consulta.

Nos dois casos, se você não chamar uma ToList()ou ToArray()então a consulta será executada toda vez que for usada, digamos que você tenha uma IQueryable<T>e preencha 4 caixas de listagem, a consulta será executada no banco de dados 4 vezes.

Além disso, se você estender sua consulta:

q.Where(x.name = "a").ToList()

Em seguida, com um IQueryable, o SQL gerado conterá "where name =" a ", mas com um IEnumerable muitas outras funções serão retiradas do banco de dados, a verificação x.name =" a "será feita pelo .NET.


10

IEnumerable está se referindo a uma coleção, mas IQueryable é apenas uma consulta e será gerada dentro de uma Expression Tree. Executaremos essa consulta para obter dados do banco de dados.


8

O pequeno teste abaixo mencionado pode ajudá-lo a entender um aspecto da diferença entre IQueryable<T>e IEnumerable<T>. Reproduzi esta resposta desta postagem em que estava tentando adicionar correções à postagem de outra pessoa

Criei a seguinte estrutura no DB (script DDL):

CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL)

Aqui está o script de inserção de registro (script DML):

INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(1, 20)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(2, 30)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(3, 40)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(4, 50)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(5, 60)
GO

Agora, meu objetivo era simplesmente obter os 2 principais registros da Employeetabela no banco de dados. Adicionei um item de modelo de dados de entidade ADO.NET ao meu aplicativo de console, apontando para a Employeetabela no meu banco de dados e comecei a escrever consultas LINQ.

Código da rota IQueryable :

using (var efContext = new EfTestEntities())
{
    IQueryable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

Quando comecei a executar este programa, também havia iniciado uma sessão do SQL Query Profiler na minha instância do SQL Server e aqui está o resumo da execução:

  1. Número total de consultas disparadas: 1
  2. Texto da consulta: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

É IQueryableinteligente o suficiente para aplicar a Top (2)cláusula no próprio servidor de banco de dados, de modo que ele traga apenas 2 de 5 registros por fio. Não é necessária nenhuma filtragem adicional na memória no lado do computador cliente.

Código para a rota IEnumerable :

using (var efContext = new EfTestEntities())
{
    IEnumerable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

Resumo da execução neste caso:

  1. Número total de consultas disparadas: 1
  2. Texto de consulta capturado no criador de perfil SQL: SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]

Agora, a coisa é IEnumerabletrazida para todos os 5 registros presentes na Salarytabela e, em seguida, executada uma filtragem na memória no computador cliente para obter os 2 principais registros. Assim, mais dados (3 registros adicionais neste caso) foram transferidos desnecessariamente pela rede.


7

Aqui está o que eu escrevi em um post semelhante (neste tópico). (E não, eu não costumo me citar, mas esses são artigos muito bons.)

"Este artigo é útil: IQueryable vs IEnumerable no LINQ-to-SQL .

Citando esse artigo, 'Conforme a documentação do MSDN, as chamadas feitas no IQueryable operam criando a árvore de expressão interna. "Esses métodos que estendem IQueryable (Of T) não realizam nenhuma consulta diretamente. Em vez disso, sua funcionalidade é criar um objeto Expression, que é uma árvore de expressão que representa a consulta cumulativa".

As árvores de expressão são uma construção muito importante em C # e na plataforma .NET. (Eles são importantes em geral, mas o C # os torna muito úteis.) Para entender melhor a diferença, recomendo ler sobre as diferenças entre expressões e declarações na especificação oficial do C # 5.0 aqui. Para conceitos teóricos avançados que se ramificam no cálculo lambda, as expressões permitem o suporte a métodos como objetos de primeira classe. A diferença entre IQueryable e IEnumerable está centrada nesse ponto. IQueryable cria árvores de expressão, enquanto IEnumerable não, pelo menos não em termos gerais, para aqueles que não trabalham nos laboratórios secretos da Microsoft.

Aqui está outro artigo muito útil que detalha as diferenças de uma perspectiva push vs. pull. (Por "push" vs. "pull", estou me referindo à direção do fluxo de dados. Técnicas de programação reativa para .NET e C #

Aqui está um artigo muito bom que detalha as diferenças entre lambdas de instrução e lambdas de expressão e discute os conceitos de árvores de expressão com mais profundidade: Revisitando representantes de C #, árvores de expressão e instruções lambda versus expressões lambda. . "


6

Usamos IEnumerablee IQueryablemanipulamos os dados recuperados do banco de dados. IQueryableherda de IEnumerable, IQueryablecontém todos os IEnumerablerecursos. A principal diferença entre IQueryablee IEnumerableé que IQueryableexecuta a consulta com filtros, enquanto IEnumerableexecuta a consulta primeiro e depois filtra os dados com base nas condições.

Encontre uma diferenciação mais detalhada abaixo:

IEnumerable

  1. IEnumerableexiste no System.Collectionsespaço para nome
  2. IEnumerable execute uma consulta de seleção no lado do servidor, carregue dados na memória no lado do cliente e depois filtre os dados
  3. IEnumerable é adequado para consultar dados de coleções na memória como List, Array
  4. IEnumerable é benéfico para consultas LINQ to Object e LINQ to XML

IQueryable

  1. IQueryableexiste no System.Linqespaço para nome
  2. IQueryable executa uma 'consulta de seleção' no lado do servidor com todos os filtros
  3. IQueryable é adequado para consultar dados de coleções de memória insuficiente (como banco de dados remoto, serviço)
  4. IQueryable é benéfico para consultas LINQ to SQL

Portanto, IEnumerablegeralmente é usado para lidar com coleções na memória, enquanto IQueryablegeralmente é usado para manipular coleções.



2

O IQueryable é mais rápido que o IEnumerable se estivermos lidando com grandes quantidades de dados do banco de dados, porque o IQueryable obtém apenas os dados necessários do banco de dados, enquanto o IEnumerable obtém todos os dados independentemente da necessidade do banco de dados.


0

ienumerable: quando queremos lidar com a memória em processo, ou seja, sem conexão de dados iqueryable: quando lidar com o servidor sql, ou seja, com a conexão de dados ilist: operações como adicionar objeto, excluir objeto etc.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.