Para que serve IQueryable
no contexto do LINQ?
É usado para o desenvolvimento de métodos de extensão ou qualquer outro propósito?
fonte
Para que serve IQueryable
no contexto do LINQ?
É usado para o desenvolvimento de métodos de extensão ou qualquer outro propósito?
A resposta de Marc Gravell é muito completa, mas pensei em acrescentar algo sobre isso do ponto de vista do usuário também ...
A principal diferença, da perspectiva do usuário, é que, quando você usa IQueryable<T>
(com um provedor que suporta as coisas corretamente), você pode economizar muitos recursos.
Por exemplo, se você estiver trabalhando em um banco de dados remoto, com muitos sistemas ORM, terá a opção de buscar dados de uma tabela de duas maneiras, uma que retorne IEnumerable<T>
e outra que retorne um IQueryable<T>
. Digamos, por exemplo, você tem uma tabela Produtos e deseja obter todos os produtos cujo custo é> US $ 25.
Se você fizer:
IEnumerable<Product> products = myORM.GetProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
O que acontece aqui é que o banco de dados carrega todos os produtos e os transmite para o seu programa. Seu programa então filtra os dados. Em essência, o banco de dados faz um SELECT * FROM Products
e retorna TODOS os produtos para você.
Com o IQueryable<T>
provedor certo , por outro lado, você pode:
IQueryable<Product> products = myORM.GetQueryableProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
O código parece o mesmo, mas a diferença aqui é que o SQL será executado SELECT * FROM Products WHERE Cost >= 25
.
Do seu POV como desenvolvedor, isso parece o mesmo. No entanto, do ponto de vista de desempenho, você só pode retornar 2 registros na rede em vez de 20.000 ....
IQueryable<Product>
- seria específico para o seu ORM ou repositório, etc.foreach
ou callToList()
), na verdade você não atinge o banco de dados.Em essência, seu trabalho é muito semelhante a
IEnumerable<T>
- para representar uma fonte de dados consultável - a diferença é que os vários métodos LINQ (ativadosQueryable
) podem ser mais específicos, para criar a consulta usandoExpression
árvores em vez de delegados (que é o queEnumerable
usa).As árvores de expressão podem ser inspecionadas pelo provedor LINQ escolhido e transformadas em uma consulta real - embora essa seja apenas uma arte negra.
Isso realmente depende do
ElementType
,Expression
eProvider
- mas, na realidade, você raramente precisa se preocupar com isso como usuário . Somente um implementador de LINQ precisa conhecer os detalhes sangrentos.Re comentários; Não sei bem o que você deseja como exemplo, mas considere o LINQ-to-SQL; o objeto central aqui é a
DataContext
, que representa nosso invólucro de banco de dados. Isso geralmente tem uma propriedade por tabela (por exemploCustomers
) e uma tabela é implementadaIQueryable<Customer>
. Mas não usamos muito diretamente; considerar:isso se torna (pelo compilador C #):
que é novamente interpretado (pelo compilador C #) como:
É importante ressaltar que os métodos estáticos nas
Queryable
árvores de expressão, que - em vez da IL regular, são compilados em um modelo de objeto. Por exemplo - basta olhar para "Onde", isso nos dá algo comparável a:O compilador não fez muito por nós? Esse modelo de objeto pode ser desmembrado, inspecionado quanto ao significado e reunido novamente pelo gerador TSQL - fornecendo algo como:
(a cadeia pode acabar como um parâmetro; não me lembro)
Nada disso seria possível se tivéssemos acabado de usar um delegado. E este é o ponto de
Queryable
/IQueryable<T>
: fornece o ponto de entrada para o uso de árvores de expressão.Tudo isso é muito complexo, por isso é um bom trabalho que o compilador o torne agradável e fácil para nós.
Para obter mais informações, consulte " C # in Depth " ou " LINQ in Action ", ambos que fornecem cobertura desses tópicos.
fonte
Embora Reed Copsey e Marc Gravell já tenham descrito sobre
IQueryable
(e tambémIEnumerable
) o suficiente, eu quero acrescentar um pouco mais aqui, fornecendo um pequeno exemploIQueryable
eIEnumerable
o número de usuários solicitados.Exemplo : Criei duas tabelas no banco de dados
A chave primária (
PersonId
) da tabelaEmployee
também é uma chave forja (personid
) da tabelaPerson
Em seguida, adicionei o modelo de entidade ado.net no meu aplicativo e criei a classe de serviço abaixo
eles contêm o mesmo linq. Ele chamou
program.cs
conforme definido abaixoA saída é a mesma para ambos, obviamente
Então a questão é qual / onde está a diferença? Não parece ter nenhuma diferença, certo? Realmente!!
Vamos dar uma olhada nas consultas sql geradas e executadas pelo framwork de entidade 5 durante esse período
Parte de execução IQueryable
Parte de execução IEnumerable
Script comum para ambas as partes de execução
Então, você tem algumas perguntas agora, deixe-me adivinhar e tentar respondê-las
Por que scripts diferentes são gerados para o mesmo resultado?
Vamos descobrir alguns pontos aqui,
todas as consultas têm uma parte comum
WHERE [Extent1].[PersonId] IN (0,1,2,3)
porque? Porque a função
IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable
eIEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable
deSomeServiceClass
contém uma linha comum nas consultas linqwhere employeesToCollect.Contains(e.PersonId)
Então, por que a
AND (N'M' = [Extent1].[Gender])
parte está faltando naIEnumerable
parte de execução, enquanto nas duas chamadas de funções usamosWhere(i => i.Gender == "M") in
program.cs`O que o framwork de entidade faz quando um
IQueryable
método é chamado, leva a instrução linq escrita dentro do método e tenta descobrir se mais expressões linq são definidas no conjunto de resultados e, em seguida, reúne todas as consultas linq definidas até que o resultado precise buscar e construa sql mais apropriado consulta para executar.Fornece muitos benefícios, como
como aqui no exemplo, o sql server retornou ao aplicativo apenas duas linhas após a execução do IQueryable`, mas retornou TRÊS linhas para a consulta IEnumerable, por que?
No caso do
IEnumerable
método, a estrutura da entidade pegou a instrução linq gravada dentro do método e constrói a consulta sql quando o resultado precisar buscar. ele não inclui resto linq parte para construir a consulta sql. Como aqui, nenhuma filtragem é feita no servidor sql na colunagender
.Mas as saídas são as mesmas? Como 'IEnumerable filtra o resultado ainda mais no nível do aplicativo após recuperar o resultado do servidor sql
Então, o que alguém deve escolher? Pessoalmente, prefiro definir o resultado da função,
IQueryable<T>
pois, como existem muitos benefíciosIEnumerable
, você pode associar duas ou mais funções IQueryable, que geram scripts mais específicos para o sql server.Aqui, no exemplo, você pode ver que
IQueryable Query(IQueryableQuery2)
gera um script mais específico doIEnumerable query(IEnumerableQuery2)
que é muito mais aceitável no meu ponto de vista.fonte
Permite mais consultas mais abaixo na linha. Se isso estivesse além do limite de serviço, o usuário desse objeto IQueryable teria permissão para fazer mais com ele.
Por exemplo, se você estiver usando carregamento lento com nhibernate, isso poderá resultar no carregamento do gráfico quando / se necessário.
fonte