Linq's let anahtar kelimesi, anahtar kelimeden daha mı iyi?


86

Şu anda LINQ fırçalama ediyorum arasındaki farkı anlamak için çalışıyorum letve kullanma intoanahtar kelime. Şimdiye kadar letkelime daha iyi görünüyor intokadarıyla benim anlayış gider anahtar kelime.

intoAnahtar kelime esasen tek bir projeksiyon sonra sorgu devam etmesini sağlar. (Açıkça belirtmek isterim ki, gruba katılmak için olana atıfta bulunmuyorum.)

Bir dizi ad verildiğinde, aşağıdakilerin yapılmasına izin verir:

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

Bu seçme sonucunu alır ve içine yerleştirir noVowel, sonra bir ek tanıtmak sağlayan değişken where, orderbyve selectcümleleri. Bir kez noVoweldeğişken oluşturulduğunda,n artık kullanılamaz.

letAnahtar kelime, diğer taraftan, bir seferde birden fazla değişkeni yeniden sağlamak için geçici anonim türleri kullanır.

Aşağıdakileri yapabilirsiniz:

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

Hem noVowelve ndeğişkenler (bu durumda kullanmadıysanız bile) kullanım için mevcuttur.

Farkı görebilsem de , önceki değişkenlerin sorgunun sonraki bölümlerinde kullanılamayacağından emin olmak istemedikçe into, letanahtar kelimeyi neden anahtar kelime yerine kullanmak isteyeceğimi tam olarak anlayamıyorum .

Peki, her iki anahtar kelimenin de var olmasının iyi bir nedeni var mı?


letÖrnekte bir yazım hatası mı - bu durumda where noVowelne var noVowel?
sll

Yanıtlar:


85

Evet, çünkü söylediğin gibi farklı şeyler yapıyorlar.

select ... intotek bir sorgunun tamamını etkili bir şekilde izole eder ve yeni bir sorgunun girdisi olarak kullanmanıza izin verir. Şahsen bunu genellikle iki değişkenle yapmayı tercih ederim:

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

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

(Kuşkusuz bu durumda bunu iki satırda nokta notasyonu ile yapardım, ama bunu görmezden gelerek ...)

Genellikle sorgunun önceki kısmının tüm bagajını istemezsiniz - bu, select ... intosorguyu yukarıdaki örneğe göre ikiye böldüğünüzde veya kullandığınızda . Bu, yalnızca sorgunun önceki bölümlerinin kullanılmaması gerektiğinde kullanılamayacağı anlamına gelmez, olup biteni basitleştirir - ve elbette her adımda potansiyel olarak daha az kopyalama olacağı anlamına gelir.

Öte yandan, ne zaman do bağlamda kalanını tutmak istiyorum, letdaha mantıklı.


9
Birinin veya diğerinin kullanımı oluşturulan SQL'i etkiler mi?
Pat Niemeyer

44

Birincil fark, letdeğişkeni intoyeni bir bağlam / kapsam oluşturduğu bağlama / kapsama enjekte etmektir .


1

DB tarafındaki farkı bilmek isteyen 2 Entity Framework sorgusu yazdı.

  • İzin Vermek

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

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

Oluşturulan SQL'ler neredeyse aynıdır . SQL mükemmel değil, aynı dize işlem kodu 2 yerde tekrarlanıyor (nerede ve seç).

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 tarafından oluşturulan SQL burada

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

Görünüşe göre Linq-to-SQL Entity Framework'ten daha akıllıdır , dize işlemi yalnızca bir kez gerçekleştirilir.


0

Leppie'nin cevabının görselleştirilmiş versiyonu . Görüldüğü gibi, derleyici sorguda hata verir intove ikincisinden farklı olarak birinci değişkene erişim sağlar.

görüntü açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.