Является ли linq let ключевым словом лучше, чем его в ключевое слово?
В настоящее время я просматриваю 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
, если только явным образом не хотел, чтобы предыдущие переменные не могли использоваться в последние части запроса.
Итак, есть ли веская причина, почему оба слова существуют?
Ответы
Ответ 1
Да, потому что они делают разные вещи, как вы сказали.
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
имеет больше смысла.
Ответ 2
Основное отличие состоит в том, что let
вводит переменную в контекст/область, где into
создает новый контекст/область.
Ответ 3
Желая узнать разницу на стороне БД, написал 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 не идеален, один и тот же код последовательности строк повторяется на 2-х местах (где и выбирать).
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, строковый процесс выполняется только один раз.