La parola chiave let di linq è migliore della sua parola chiave into?


86

Attualmente sto ripassando su LINQ e sto cercando di comprendere la differenza tra lete utilizzando la intoparola chiave. Finora la letparola chiave sembra migliore della intoparola chiave per quanto ne so .

La intoparola chiave consente essenzialmente di continuare una query dopo una proiezione. (Voglio solo affermare esplicitamente che non mi riferisco a quello per l'adesione al gruppo.)

Dato un array di nomi consente di fare quanto segue:

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

Prende il risultato della selezione e la pone nella noVowelvariabile che poi permette di introdurre ulteriori where, orderbye selectle clausole. Una volta noVowelcreata la nvariabile , la variabile non è più disponibile.

La letparola chiave, d'altra parte, utilizza tipi temporanei anonimi per consentire di riutilizzare più di una variabile alla volta.

Puoi fare quanto segue:

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

Entrambe le variabili noVowele nsono disponibili per l'uso (anche se non l'ho usato in questo caso).

Anche se posso vedere la differenza, non riesco a capire perché si desideri utilizzare la intoparola chiave sulla parola letchiave a meno che non si volesse esplicitamente assicurarsi che le variabili precedenti non potessero essere utilizzate nelle ultime parti della query.

Quindi, c'è una buona ragione per cui esistono entrambe le parole chiave?


È un errore di battitura in letesempio - where noVowel, cosa c'è noVowelin quel caso?
fino al

Risposte:


85

Sì, perché stanno facendo cose diverse, come hai detto tu.

select ... intoisola efficacemente l'intera query e consente di utilizzarla come input per una nuova query. Personalmente di solito preferisco farlo tramite due variabili:

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

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

(Certo in questo caso lo farei con la notazione del punto su due righe, ma ignorandolo ...)

Spesso non si desidera l'intero bagaglio della parte precedente della query, ovvero quando si utilizza select ... intoo si divide la query in due come nell'esempio precedente. Non solo ciò significa che le parti precedenti della query non possono essere utilizzate quando non dovrebbero esserlo, ma semplifica ciò che sta accadendo e, naturalmente, significa che ci sono potenzialmente meno copie in corso ad ogni passaggio.

D'altra parte, quando si fa desidera mantenere il resto del contesto, letha più senso.


9
L'utilizzo dell'uno o dell'altro influisce sull'SQL generato?
Pat Niemeyer

44

La differenza principale è l' letinserimento della variabile nel contesto / ambito, dove intocrea un nuovo contesto / ambito.


1

Volendo conoscere la differenza sul lato DB, ha scritto 2 query di Entity Framework.

  • Permettere

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

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

Gli SQL generati sono quasi identici . L'SQL non è perfetto, lo stesso codice di processo stringa viene ripetuto in 2 punti (dove e seleziona).

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

Ecco l'SQL generato da 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

Sembra che Linq-to-SQL sia più intelligente di Entity Framework, il processo di stringa viene eseguito solo una volta.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.