Linq 的 let 关键字比 into 关键字好吗?

我目前正在温习 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关键字,除非明确地想要确保前面的变量不能在查询的后面部分使用。

那么,为什么两个关键字都存在呢?

27248 次浏览

Yes, because they're doing different things, as you've said.

select ... into effectively isolates the whole of one query and lets you use it as the input to a new query. Personally I usually prefer to do this via two variables:

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


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

(Admittedly in this case I would do it with dot notation in two lines, but ignoring that...)

Often you don't want the whole baggage of the earlier part of the query - which is when you use select ... into or split the query in two as per the above example. Not only does that mean the earlier parts of the query can't be used when they shouldn't be, it simplifies what's going on - and of course it means there's potentially less copying going on at each step.

On the other hand, when you do want to keep the rest of the context, let makes more sense.

The primary difference is the let injects the variable into the context/scope, where into creates a new context/scope.

Wanting to know the difference on DB side, wrote 2 Entity Framework queries.

  • Let

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

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

The generated SQLs are almost identical. The SQL is not perfect, same string process code are repeated on 2 places (where and 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

Here is the SQL generated by 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

Seems Linq-to-SQL is smarter than Entity Framework, string process performed only once.

Visualized version of leppie's answer. As can be seen, the compiler yields error in the query with into unlike the latter one as accessing to first variable.

enter image description here