linqのletキーワードはintoキーワードよりも優れていますか?


86

私は現在LINQをブラッシュアップしletており、intoキーワードとキーワードの使用の違いを理解しようとしています。私の理解では、これまでのところ、letキーワードはキーワードよりも優れintoているようです。

intoキーワードは、本質的に1投影後にクエリを継続することができます。(グループ参加用のものを参照していないことを明示的に述べたいだけです。)

名前の配列が与えられると、次のことが可能になります。

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

これは、選択の結果を取り、にそれを置きnoVowel、その後1を追加導入することができます変数whereorderbyおよびselect句。一度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 noVowelnoVowelその場合はどうなりますか?
sll 2012年

回答:


85

はい、あなたが言ったように、彼らは異なることをしているので。

select ... into1つのクエリ全体を効果的に分離し、それを新しいクエリへの入力として使用できるようにします。個人的に私は通常、 2つの変数を介してこれを行うことを好みます。

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

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

(確かにこの場合、2行のドット表記で行いますが、それは無視します...)

多くの場合、あなたはしていないしたいあなたが使用している場合である-クエリの以前の一部の全部荷物select ... intoまたは上記の例のように2つにクエリを分割します。これは、クエリの前の部分を使用すべきでないときに使用できないことを意味するだけでなく、何が起こっているかを単純化します。もちろん、各ステップで行われるコピーが少なくなる可能性があることを意味します。

一方、残りのコンテキストを保持たい場合letより理にかなっています。


9
どちらを使用しても、生成されるSQLに影響しますか?
Pat Niemeyer 2012年

44

主な違いは、let変数をコンテキスト/スコープに挿入しinto、新しいコンテキスト/スコープを作成することです。


1

DB側の違いを知りたくて、2つのEntityFrameworkクエリを作成しました。

  • しましょう

    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はEntityFrameworkより賢く、文字列プロセスは1回だけ実行されるようです。


0

レピーの答えの視覚化されたバージョン。見てわかるように、コンパイラintoは、最初の変数にアクセスする場合の後者とは異なり、クエリでエラーを生成します。

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.