Чи є ключове слово linq's let краще, ніж його ключове слово?


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?
Pat Niemeyer,

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 не ідеальний, той самий код рядкового процесу повторюється у 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, рядовий процес виконується лише один раз.


0

Візуалізована версія відповіді леппі . Як бачимо, компілятор видає помилку в запиті, на intoвідміну від останнього як доступ до першої змінної.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.