Qual é a diferença entre IQueryable<T>
e IEnumerable<T>
?
Consulte também Qual é a diferença entre IQueryable e IEnumerable que se sobrepõe a esta pergunta.
Qual é a diferença entre IQueryable<T>
e IEnumerable<T>
?
Consulte também Qual é a diferença entre IQueryable e IEnumerable que se sobrepõe a esta pergunta.
Respostas:
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.
AsQueryable()
apenas converterá um enumerável em um questionável e o retornará se implementar a IQueryable
interface; caso contrário, ele o envolverá em um ConstantExpression
, que é referido em um EnumerableQuery
objeto retornado .
A principal diferença é que os operadores LINQ IQueryable<T>
recebem Expression
objetos 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.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:
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 IQueryable
interface herdada de IEnumerable
, portanto, o que quer que IEnumerable
possa fazer, IQueryable
também pode fazer.
Existem muitas diferenças, mas vamos discutir sobre a grande diferença que faz a maior diferença. IEnumerable
A interface é útil quando sua coleção é carregada usando a LINQ
estrutura Entity e você deseja aplicar um filtro à coleção.
Considere o código simples abaixo que usa IEnumerable
com a estrutura da entidade. Está usando um Where
filtro 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 IEnumerable
código. Em outras palavras, todos os dados são buscados no banco de dados e, em seguida, no cliente, as varreduras e o registro EmpId
são 2
.
Mas agora veja o código abaixo mudamos IEnumerable
para 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>();
Portanto, a diferença entre IQueryable
e 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.
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
Na vida real, se você estiver usando um ORM como LINQ-to-SQL
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.
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 Employee
tabela no banco de dados. Adicionei um item de modelo de dados de entidade ADO.NET ao meu aplicativo de console, apontando para a Employee
tabela 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:
SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]
É IQueryable
inteligente 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:
SELECT [Extent1].[Salary] AS [Salary]
FROM [dbo].[Employee] AS [Extent1]
Agora, a coisa é IEnumerable
trazida para todos os 5 registros presentes na Salary
tabela 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.
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. . "
Usamos IEnumerable
e IQueryable
manipulamos os dados recuperados do banco de dados. IQueryable
herda de IEnumerable
, IQueryable
contém todos os IEnumerable
recursos. A principal diferença entre IQueryable
e IEnumerable
é que IQueryable
executa a consulta com filtros, enquanto IEnumerable
executa a consulta primeiro e depois filtra os dados com base nas condições.
Encontre uma diferenciação mais detalhada abaixo:
IEnumerable
IEnumerable
existe no System.Collections
espaço para nomeIEnumerable
execute uma consulta de seleção no lado do servidor, carregue dados na memória no lado do cliente e depois filtre os dadosIEnumerable
é adequado para consultar dados de coleções na memória como List, ArrayIEnumerable
é benéfico para consultas LINQ to Object e LINQ to XMLIQueryable
IQueryable
existe no System.Linq
espaço para nomeIQueryable
executa uma 'consulta de seleção' no lado do servidor com todos os filtrosIQueryable
é adequado para consultar dados de coleções de memória insuficiente (como banco de dados remoto, serviço)IQueryable
é benéfico para consultas LINQ to SQLPortanto, IEnumerable
geralmente é usado para lidar com coleções na memória, enquanto IQueryable
geralmente é usado para manipular coleções.
IEnumerable e IQueryable são usados para armazenar a coleta de dados e executar operações de manipulação de dados, por exemplo, filtragem na coleta de dados. Aqui você pode encontrar a melhor comparação de diferenças com o exemplo. http://www.gurujipoint.com/2017/05/difference-between-ienumerable-and.html
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.
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.