Apakah kata kunci LINQ lebih baik daripada kata kunci dalam?

86

Saya sedang mempelajari kembali LINQ dan mencoba memahami perbedaan antara letdan menggunakan intokata kunci. Sejauh ini letkata kunci tampaknya lebih baik daripada intokata kunci sejauh pemahaman saya.

Kata intokunci pada dasarnya memungkinkan seseorang untuk melanjutkan kueri setelah proyeksi. (Hanya ingin menyatakan secara eksplisit bahwa saya tidak merujuk ke grup untuk bergabung.)

Diberikan berbagai nama, memungkinkan seseorang untuk melakukan hal berikut:

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

Dibutuhkan hasil pilih dan tempat ke dalam noVowelvariabel yang kemudian memungkinkan seseorang untuk memperkenalkan tambahan where, orderbydan selectklausa. Setelah noVowelvariabel dibuat, nvariabel tersebut tidak lagi tersedia.

Sebaliknya let, kata kunci menggunakan jenis anonim sementara untuk memungkinkan Anda menggunakan kembali lebih dari satu variabel dalam satu waktu.

Anda dapat melakukan hal berikut:

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

Baik variabel noVoweldan ntersedia untuk digunakan (meskipun saya belum menggunakannya dalam kasus ini).

Meskipun saya dapat melihat perbedaannya, saya tidak begitu mengerti mengapa seseorang ingin menggunakan intokata kunci di atas letkata kunci kecuali seseorang secara eksplisit ingin memastikan bahwa variabel sebelumnya tidak dapat digunakan di bagian akhir kueri.

Jadi, adakah alasan bagus mengapa kedua kata kunci tersebut ada?

mezoid
sumber
Apakah itu salah ketik dalam letcontoh - where noVowel, apa noVoweldalam kasus itu?
sll

Jawaban:

85

Ya, karena mereka melakukan hal yang berbeda, seperti yang Anda katakan.

select ... intosecara efektif mengisolasi keseluruhan satu kueri dan memungkinkan Anda menggunakannya sebagai masukan untuk kueri baru. Secara pribadi saya biasanya lebih suka melakukan ini melalui dua variabel:

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

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

(Memang dalam hal ini saya akan melakukannya dengan notasi titik dalam dua baris, tetapi mengabaikannya ...)

Seringkali Anda tidak menginginkan seluruh bagasi dari bagian awal kueri - yaitu saat Anda menggunakanselect ... into atau membagi kueri menjadi dua seperti contoh di atas. Tidak hanya itu berarti bagian awal dari kueri tidak dapat digunakan pada saat yang tidak semestinya, tetapi juga menyederhanakan apa yang terjadi - dan tentu saja itu berarti kemungkinan penyalinan berkurang di setiap langkah.

Di sisi lain, jika Anda memang ingin mempertahankan konteks lainnya, letlebih masuk akal.

Jon Skeet
sumber
9
Apakah penggunaan salah satu atau yang lain memengaruhi SQL yang dihasilkan?
Pat Niemeyer
44

Perbedaan utamanya adalah letmemasukkan variabel ke dalam konteks / cakupan, di mana intomembuat konteks / cakupan baru.

leppie
sumber
1

Ingin mengetahui perbedaan di sisi DB, tulis 2 kueri Entity Framework.

  • Membiarkan

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

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

SQL yang dihasilkan hampir identik . SQL tidak sempurna, kode proses string yang sama diulangi di 2 tempat (di mana dan pilih).

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

Berikut adalah SQL yang dihasilkan oleh 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

Sepertinya Linq-to-SQL lebih pintar dari Entity Framework, proses string hanya dilakukan sekali.

Rm558
sumber
0

Versi visual dari jawaban leppie . Seperti yang bisa dilihat, kompilator menghasilkan kesalahan dalam kueri dengan intotidak seperti yang terakhir saat mengakses variabel pertama.

masukkan deskripsi gambar di sini

snr
sumber