linq的let关键字是否比它的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变量,然后允许一个引入额外的whereorderbyselect条款。一旦noVowel变量被创建,该n变量不再可用。

let关键字,而另一方面,使用温度匿名类型,让你在同一时间重复使用一个以上的变量。

您可以执行以下操作:

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

无论是noVoweln变量都可以使用(尽管我没有在这种情况下使用它)。

虽然我可以看到区别,但是我不能完全理解为什么要使用该into关键字而不是该let关键字,除非有人明确希望确保先前的变量不能在查询的后半部分使用。

那么,这两个关键字同时存在有充分的理由吗?


let示例中是否有错字- where noVowel,那是什么noVowel情况?
2012年

Answers:


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 2012年

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个地方(where和select)重复相同的字符串处理代码。

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

这是LINQ-to-SQL生成的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与后者不同的是访问第一个变量。

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.