A palavra-chave let do linq é melhor do que a palavra-chave into?

86

Atualmente, estou aprimorando o LINQ e tentando compreender a diferença entre lete usando a intopalavra - chave. Até agora, a letpalavra - chave parece melhor do que a intopalavra - chave, pelo que entendi.

A intopalavra-chave permite essencialmente continuar uma consulta após uma projeção. (Só quero declarar explicitamente que não estou me referindo àquele para entrar em grupo.)

Dado um conjunto de nomes, permite fazer o seguinte:

var intoQuery =
  from n in names
  select Regex.Replace(n, "[aeiou]", "")
  into noVowel
  where noVowel.Length > 2
  select noVowel;

Leva o resultado do select e coloca-o na noVowelvariável que permite então que a introduzir adicionais where, orderbye selectcláusulas. Depois que a noVowelvariável é criada, ela nnão está mais disponível.

A letpalavra-chave, por outro lado, usa tipos anônimos temporários para permitir que você reutilize mais de uma variável por vez.

Você pode fazer o seguinte:

var letQuery =
  from n in names
  let noVowel = Regex.Replace(n, "[aeiou]", "")
  where noVowel.Length > 2
  select noVowel;

As variáveis noVowele nestão disponíveis para uso (embora eu não tenha usado neste caso).

Embora eu possa ver a diferença, não consigo entender por que alguém iria querer usar a intopalavra-chave em vez da palavra- letchave, a menos que alguém quisesse explicitamente ter certeza de que as variáveis ​​anteriores não puderam ser usadas nas últimas partes da consulta.

Então, há um bom motivo para as duas palavras-chave existirem?

mezóide
fonte
É um erro de digitação no letexemplo - o where noVowelque é noVowelnesse caso?
SLL

Respostas:

85

Sim, porque estão fazendo coisas diferentes, como você disse.

select ... intoisola efetivamente toda uma consulta e permite que você a use como entrada para uma nova consulta. Pessoalmente, geralmente prefiro fazer isso por meio de duas variáveis:

var tmp = from n in names
          select Regex.Replace(n, "[aeiou]", "");

var noVowels = from noVowel in tmp
               where noVowel.Length > 2
               select noVowel;

(É certo que, neste caso, faria isso com a notação de ponto em duas linhas, mas ignorando isso ...)

Freqüentemente, você não quer toda a bagagem da parte anterior da consulta - que é quando você usa select ... intoou divide a consulta em duas, conforme o exemplo acima. Isso não apenas significa que as partes anteriores da consulta não podem ser usadas quando não deveriam, mas simplifica o que está acontecendo - e é claro que significa que há potencialmente menos cópias em cada etapa.

Por outro lado, quando você não quiser manter o resto do contexto, letfaz mais sentido.

Jon Skeet
fonte
9
O uso de um ou de outro afeta o SQL gerado?
Pat Niemeyer
44

A principal diferença é que letinjeta a variável no contexto / escopo, onde intocria um novo contexto / escopo.

leppie
fonte
1

Querendo saber a diferença no lado do banco de dados, escreveu 2 consultas do Entity Framework.

  • Deixei

    from u in Users
    let noVowel = u.FirstName.Replace("a","").Replace("e","").Replace("i","")
    where noVowel.Length >5
    select new {u.FirstName, noVowel}
    
  • Para dentro

    from u in Users
    select u.FirstName.Replace("a","").Replace("e","").Replace("i","")
    into noVowel
    where noVowel.Length >5
    select noVowel
    

Os SQLs gerados são quase idênticos . O SQL não é perfeito, o mesmo código de processo de string é repetido em 2 lugares (onde e selecione).

SELECT 1 AS [C1], [Extent1].[FirstName] AS [FirstName], 
REPLACE(REPLACE(REPLACE([Extent1].[FirstName], N'a', N''), N'e', N''), N'i', N'') AS [C2]
FROM [dbo].[User] AS [Extent1]
WHERE ( CAST(LEN(REPLACE(REPLACE(REPLACE([Extent1].[FirstName], N'a', N''), N'e', N''), N'i', N'')) AS int)) > 5
GO

SELECT 
REPLACE(REPLACE(REPLACE([Extent1].[FirstName], N'a', N''), N'e', N''), N'i', N'') AS [C1]
FROM [dbo].[User] AS [Extent1]
WHERE ( CAST(LEN(REPLACE(REPLACE(REPLACE([Extent1].[FirstName], N'a', N''), N'e', N''), N'i', N'')) AS int)) > 5

Aqui está o SQL gerado pelo LINQ-to-SQL

-- Region Parameters
DECLARE @p0 NVarChar(1000) = 'a'
DECLARE @p1 NVarChar(1000) = ''
DECLARE @p2 NVarChar(1000) = 'e'
DECLARE @p3 NVarChar(1000) = ''
DECLARE @p4 NVarChar(1000) = 'i'
DECLARE @p5 NVarChar(1000) = ''
DECLARE @p6 Int = 5
-- EndRegion
SELECT [t1].[FirstName], [t1].[value] AS [noVowel]
FROM (
    SELECT [t0].[FirstName], REPLACE(REPLACE(REPLACE([t0].[FirstName], @p0, @p1), @p2, @p3), @p4, @p5) AS [value]
    FROM [User] AS [t0]
    ) AS [t1]
WHERE LEN([t1].[value]) > @p6
GO

-- Region Parameters
DECLARE @p0 NVarChar(1000) = 'a'
DECLARE @p1 NVarChar(1000) = ''
DECLARE @p2 NVarChar(1000) = 'e'
DECLARE @p3 NVarChar(1000) = ''
DECLARE @p4 NVarChar(1000) = 'i'
DECLARE @p5 NVarChar(1000) = ''
DECLARE @p6 Int = 5
-- EndRegion
SELECT [t1].[value]
FROM (
    SELECT REPLACE(REPLACE(REPLACE([t0].[FirstName], @p0, @p1), @p2, @p3), @p4, @p5) AS [value]
    FROM [User] AS [t0]
    ) AS [t1]
WHERE LEN([t1].[value]) > @p6

Parece que o Linq-to-SQL é mais inteligente do que o Entity Framework, processo de string executado apenas uma vez.

Rm558
fonte
0

Versão visualizada da resposta de leppie . Como pode ser visto, o compilador produz erro na consulta ao intocontrário da última no acesso à primeira variável.

insira a descrição da imagem aqui

snr
fonte