我正在刷新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;
它会将select的结果放入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
关键字,除非明确要确保以前的变量无法使用用于查询的后半部分。
那么,两个关键词存在的原因是否充分?
答案 0 :(得分:83)
是的,因为他们正在做不同的事情,正如你所说的那样。
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
更有意义。
答案 1 :(得分:43)
主要区别是let
将变量注入上下文/范围,其中into
创建新的上下文/范围。
答案 2 :(得分:1)
想要了解数据库方面的差异,编写了2个实体框架查询。
让
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比实体框架更智能,字符串进程只执行一次。
答案 3 :(得分:0)
leppie's answer的可视化版本。
可以看出,编译器在使用into
的查询中产生错误,不像后者访问第一个变量那样。