Ключевое слово let в linq лучше, чем ключевое слово into?

86

Я в настоящее время отрабатывает на LINQ и пытаюсь понять разницу между letи с помощью intoключевого слова. Насколько я понимаю, letключевое слово кажется лучше, чем intoключевое слово.

intoКлючевое слово , по существу , позволяет продолжить запрос после прогноза. (Просто хочу прямо заявить, что я не говорю о присоединении к группе.)

Имея массив имен, он позволяет делать следующее:

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

Он принимает результат избранных и помещает его в noVowelпеременную , которая затем позволяет ввести дополнительное where, orderbyи selectположение. После noVowelсоздания nпеременной она больше не доступна.

letКлючевое слово, с другой стороны, использует временные анонимные типы , чтобы повторно использовать более одной переменной в то время.

Вы можете сделать следующее:

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

Как noVowelи nпеременные доступны для использования (хотя я не использовал его в данном случае).

Хотя я вижу разницу, я не совсем понимаю, почему нужно использовать intoключевое letслово вместо ключевого слова, если только кто-то явно не хочет убедиться, что предыдущие переменные не могут использоваться в последних частях запроса.

Итак, есть ли веская причина, по которой существуют оба ключевых слова?

мезоид
источник
Это опечатка в letпримере - where noVowelчто noVowelв этом случае?
sll

Ответы:

85

Да, потому что, как вы сказали, они делают разные вещи.

select ... intoэффективно изолирует весь один запрос и позволяет использовать его в качестве входных данных для нового запроса. Лично я обычно предпочитаю делать это с помощью двух переменных:

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

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

(По общему признанию, в этом случае я бы сделал это с точечной нотацией в две строки, но проигнорировал это ...)

Часто вам не нужен весь багаж предыдущей части запроса - это когда вы используете select ... intoили разделяете запрос на два, как в приведенном выше примере. Это не только означает, что более ранние части запроса не могут использоваться, когда они не должны использоваться, но и упрощает то, что происходит, и, конечно же, означает, что на каждом этапе потенциально меньше копий.

С другой стороны, если вы действительно хотите сохранить остальную часть контекста, letимеет больше смысла.

Джон Скит
источник
9
Влияет ли использование одного или другого на сгенерированный SQL?
Пэт Нимейер
44

Основное отличие заключается в letтом, что переменная intoвводится в контекст / область видимости, где создается новый контекст / область видимости.

леппи
источник
1

Желая узнать разницу на стороне БД, написал 2 запроса Entity Framework.

  • Позволять

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

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

Сгенерированные SQL-запросы практически идентичны . SQL не идеален, один и тот же строковый код процесса повторяется в двух местах (где и выберите).

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

Вот SQL, созданный 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

Кажется, Linq-to-SQL умнее Entity Framework, строковый процесс выполняется только один раз.

Rm558
источник
0

Визуализированная версия ответа леппи . Как видно, компилятор выдает ошибку в запросе, в intoотличие от последнего, как доступ к первой переменной.

введите описание изображения здесь

snr
источник