C'de LINQ Sorgularına Giriş#

Sorgu, veri kaynağından veri alan bir ifadedir. Farklı veri kaynakları, ilişkisel veritabanları için SQL ve XML için XQuery gibi farklı yerel sorgu dillerine sahiptir. Geliştiricilerin desteklemesi gereken her veri kaynağı veya veri biçimi türü için yeni bir sorgu dili öğrenmesi gerekir. LINQ, veri kaynağı ve biçim türleri için tutarlı bir C# dil modeli sunarak bu durumu basitleştirir. LINQ sorgusunda her zaman C# nesneleriyle çalışırsınız. BIR LINQ sağlayıcısı kullanılabilir olduğunda XML belgelerindeki, SQL veritabanlarındaki, .NET koleksiyonlarındaki ve diğer biçimlerdeki verileri sorgulamak ve dönüştürmek için aynı temel kodlama desenlerini kullanırsınız.

Bir Sorgu İşleminin Üç Bölümü

Tüm LINQ sorgu işlemleri üç ayrı eylemden oluşur:

  1. Veri kaynağını alın.
  2. Sorguyu oluşturun.
  3. Sorguyu çalıştırın.

Aşağıdaki örnekte, bir sorgu işleminin üç bölümünün kaynak kodunda nasıl ifade edildiği gösterilmektedir. Örnekte kolaylık sağlamak için veri kaynağı olarak bir tamsayı dizisi kullanılır; ancak, aynı kavramlar diğer veri kaynakları için de geçerlidir. Bu örnek, bu makalenin geri kalanında başvuruda bulunulacaktır.

// The Three Parts of a LINQ Query:
// 1. Data source.
int[] numbers = [ 0, 1, 2, 3, 4, 5, 6 ];

// 2. Query creation.
// numQuery is an IEnumerable<int>
var numQuery =
    from num in numbers
    where (num % 2) == 0
    select num;

// 3. Query execution.
foreach (int num in numQuery)
{
    Console.Write("{0,1} ", num);
}

Aşağıdaki çizimde sorgu işleminin tamamı gösterilmektedir. LINQ'de, sorgunun yürütülmesi sorgunun kendisinden farklıdır. Başka bir deyişle, sorgu değişkeni oluşturarak herhangi bir veri almazsınız.

Tam LINQ sorgu işleminin diyagramı.

Veri Kaynağı

Yukarıdaki örnekteki veri kaynağı, genel IEnumerable<T> arabirimi destekleyen bir dizidir. Bu gerçek, LINQ ile sorgulanabileceği anlamına gelir. Sorgu bir foreach deyimde yürütülür ve foreach veya IEnumerable<T>gerektirirIEnumerable. Destekleyen IEnumerable<T> türler veya genel IQueryable<T> gibi türetilmiş arabirimler sorgulanabilir türler olarak adlandırılır.

Sorgulanabilir bir tür, LINQ veri kaynağı olarak hizmet vermek için değişiklik veya özel işlem gerektirmez. Kaynak veriler sorgulanabilir bir tür olarak bellekte değilse, LINQ sağlayıcısı bunu bu şekilde temsil etmelidir. Örneğin, LINQ to XML bir XML belgesini sorgulanabilir XElement bir türe yükler:

// Create a data source from an XML document.
// using System.Xml.Linq;
XElement contacts = XElement.Load(@"c:\myContactList.xml");

EntityFramework ile C# sınıfları ile veritabanı şemanız arasında nesne ilişkisel eşleme oluşturursunuz. Sorgularınızı nesnelere yazarsınız ve çalışma zamanında EntityFramework veritabanıyla iletişimi işler. Aşağıdaki örnekte veritabanındaki Customers belirli bir tabloyu temsil eder ve sorgu sonucunun türü , IQueryable<T>türünden IEnumerable<T>türetilir.

Northwnd db = new Northwnd(@"c:\northwnd.mdf");

// Query for customers in London.
IQueryable<Customer> custQuery =
    from cust in db.Customers
    where cust.City == "London"
    select cust;

Belirli veri kaynağı türlerini oluşturma hakkında daha fazla bilgi için çeşitli LINQ sağlayıcılarının belgelerine bakın. Ancak temel kural basittir: LINQ veri kaynağı, genel IEnumerable<T> arabirimi destekleyen herhangi bir nesne veya genellikle ondan IQueryable<T>devralan bir arabirimdir.

Not

Genel IEnumerable olmayan arabirimi destekleyen türler ArrayList LINQ veri kaynağı olarak da kullanılabilir. Daha fazla bilgi için bkz . LINQ (C#) ile ArrayList sorgulama.

Sorgu

Sorgu, veri kaynağından veya kaynaklardan alınacak bilgileri belirtir. İsteğe bağlı olarak, sorgu bu bilgilerin döndürülmeden önce nasıl sıralanacağını, gruplandırılmasını ve şekillendirilmesi gerektiğini de belirtir. Sorgu bir sorgu değişkeninde depolanır ve sorgu ifadesiyle başlatılır. Sorgu yazmak için C# sorgu söz dizimlerini kullanırsınız.

Önceki örnekteki sorgu, tamsayı dizisindeki tüm çift sayıları döndürür. Sorgu ifadesi üç yan tümce içerir: from, whereve select. (SQL hakkında bilginiz varsa, yan tümcelerinin sırasının SQL'deki sıraylan ters çevrildiğini fark ettiniz.) from yan tümcesi veri kaynağını, where yan tümcesi filtreyi uygular ve select yan tümcesi döndürülen öğelerin türünü belirtir. Tüm sorgu yan tümceleri bu bölümde ayrıntılı olarak açıklanmıştır. Şimdilik önemli nokta, LINQ'te sorgu değişkeninin hiçbir işlem gerçekleştirmesi ve veri döndürmesidir. Yalnızca sorgu daha sonraki bir noktada yürütülürken sonuçları üretmek için gereken bilgileri depolar. Sorguların nasıl oluşturulur hakkında daha fazla bilgi için bkz . Standart Sorgu İşleçlerine Genel Bakış (C#).

Not

Sorgular, yöntem söz dizimi kullanılarak da ifade edilebilir. Daha fazla bilgi için bkz . LINQ'te Sorgu Sözdizimi ve Yöntem Sözdizimi.

Standart sorgu işleçlerinin yürütme şekline göre sınıflandırılması

Standart sorgu işleci yöntemlerinin LINQ to Objects uygulamaları iki ana yoldan biriyle yürütülür: anında veya ertelenmiş. Ertelenmiş yürütme kullanan sorgu işleçleri ek olarak iki kategoriye ayrılabilir: akış ve akışsız.

Anlık

Anında yürütme, veri kaynağının okunduğu ve işlemin bir kez gerçekleştirildiği anlamına gelir. Skaler sonuç döndüren tüm standart sorgu işleçleri hemen yürütülür. Bu tür sorgulara örnek olarak Count, Max, Averageve Firstverilebilir. Sorgunun bir sonuç döndürmek için kullanması foreach gerektiğinden, bu yöntemler açık foreach bir deyim olmadan yürütülür. Bu sorgular koleksiyon değil tek bir IEnumerable değer döndürür. veya Enumerable.ToArray yöntemlerini kullanarak herhangi bir sorguyu Enumerable.ToList hemen yürütülmeye zorlayabilirsiniz. Anında yürütme, sorgu bildirimini değil sorgu sonuçlarının yeniden kullanılmasını sağlar. Sonuçlar bir kez alınır ve daha sonra kullanılmak üzere depolanır. Aşağıdaki sorgu, kaynak dizideki çift sayıların sayısını döndürür:

var evenNumQuery =
    from num in numbers
    where (num % 2) == 0
    select num;

int evenNumCount = evenNumQuery.Count();

Herhangi bir sorgunun hemen yürütülmesini zorlamak ve sonuçlarını önbelleğe almak için veya ToArray yöntemlerini çağırabilirsinizToList.

List<int> numQuery2 =
    (from num in numbers
        where (num % 2) == 0
        select num).ToList();

// or like this:
// numQuery3 is still an int[]

var numQuery3 =
    (from num in numbers
        where (num % 2) == 0
        select num).ToArray();

Ayrıca sorgu ifadesinin foreach hemen arkasına döngü koyarak yürütmeyi zorlayabilirsiniz. Ancak, çağırarak ToList veya ToArray tüm verileri tek bir koleksiyon nesnesinde önbelleğe alırsınız.

Ertelenmiş

Ertelenmiş yürütme, işlemin sorgunun bildirildiği kod noktasında gerçekleştirilmiyor olduğu anlamına gelir. İşlem yalnızca sorgu değişkeni numaralandırıldığında, örneğin bir foreach deyimi kullanılarak gerçekleştirilir. Sorguyu yürütmenin sonuçları, sorgu tanımlandığında değil, sorgu yürütülürken veri kaynağının içeriğine bağlıdır. Sorgu değişkeni birden çok kez numaralandırılırsa, sonuçlar her seferinde farklı olabilir. Dönüş türü IEnumerable<T> ertelenmiş bir şekilde olan veya IOrderedEnumerable<TElement> yürütülen neredeyse tüm standart sorgu işleçleri. Ertelenmiş yürütme, sorgu sonuçları her yinelendiğinde sorgu güncelleştirilmiş verileri veri kaynağından aldığından sorgunun yeniden kullanılmasını sağlar. Aşağıdaki kod, ertelenmiş yürütme örneğini gösterir:

foreach (int num in numQuery)
{
    Console.Write("{0,1} ", num);
}

Deyimi foreach , sorgu sonuçlarının da alındığı yerdir. Örneğin, önceki sorguda yineleme değişkeni num döndürülen dizideki her değeri (birer birer) tutar.

Sorgu değişkeninin kendisi sorgu sonuçlarını hiçbir zaman tutmadığından, güncelleştirilmiş verileri almak için bunu tekrar tekrar yürütebilirsiniz. Örneğin, ayrı bir uygulama veritabanını sürekli güncelleştirebilir. Uygulamanızda, en son verileri alan bir sorgu oluşturabilir ve güncelleştirilmiş sonuçları almak için bu sorguyu aralıklarla yürütebilirsiniz.

Ertelenmiş yürütme kullanan sorgu işleçleri ek olarak akış veya akışsız olarak sınıflandırılabilir.

Akışlar

Akış işleçlerinin öğeleri sağlamadan önce tüm kaynak verileri okuması gerekmez. Yürütme sırasında, bir akış işleci her kaynak öğe üzerinde okundukça işlemini gerçekleştirir ve uygunsa öğesini verir. Akış işleci, sonuç öğesi üretilene kadar kaynak öğeleri okumaya devam eder. Bu, bir sonuç öğesi üretmek için birden fazla kaynak öğenin okunabileceği anlamına gelir.

Akışsız

Akışsız işleçlerin bir sonuç öğesi elde etmeden önce tüm kaynak verileri okuması gerekir. Sıralama veya gruplandırma gibi işlemler bu kategoriye girer. Yürütme sırasında, akışsız sorgu işleçleri tüm kaynak verileri okur, bir veri yapısına ekler, işlemi gerçekleştirir ve sonuçta elde edilen öğeleri verir.

Sınıflandırma tablosu

Aşağıdaki tablo, her standart sorgu işleci yöntemini yürütme yöntemine göre sınıflandırır.

Not

bir işleç iki sütunda işaretlenmişse, işleme iki giriş dizisi dahil edilir ve her dizi farklı değerlendirilir. Bu gibi durumlarda, her zaman parametre listesindeki ertelenmiş, akış biçiminde değerlendirilen ilk sıradır.

Standart sorgu işleci Dönüş türü Anında yürütme Ertelenen akış yürütme Ertelenmiş akışsız yürütme
Aggregate TSource X
All Boolean X
Any Boolean X
AsEnumerable IEnumerable<T> X
Average Tek sayısal değer X
Cast IEnumerable<T> X
Concat IEnumerable<T> X
Contains Boolean X
Count Int32 X
DefaultIfEmpty IEnumerable<T> X
Distinct IEnumerable<T> X
ElementAt TSource X
ElementAtOrDefault TSource? X
Empty IEnumerable<T> X
Except IEnumerable<T> X X
First TSource X
FirstOrDefault TSource? X
GroupBy IEnumerable<T> X
GroupJoin IEnumerable<T> X X
Intersect IEnumerable<T> X X
Join IEnumerable<T> X X
Last TSource X
LastOrDefault TSource? X
LongCount Int64 X
Max Tek sayısal değer, TSourceveya TResult? X
Min Tek sayısal değer, TSourceveya TResult? X
OfType IEnumerable<T> X
OrderBy IOrderedEnumerable<TElement> X
OrderByDescending IOrderedEnumerable<TElement> X
Range IEnumerable<T> X
Repeat IEnumerable<T> X
Reverse IEnumerable<T> X
Select IEnumerable<T> X
SelectMany IEnumerable<T> X
SequenceEqual Boolean X
Single TSource X
SingleOrDefault TSource? X
Skip IEnumerable<T> X
SkipWhile IEnumerable<T> X
Sum Tek sayısal değer X
Take IEnumerable<T> X
TakeWhile IEnumerable<T> X
ThenBy IOrderedEnumerable<TElement> X
ThenByDescending IOrderedEnumerable<TElement> X
ToArray TSource[] Dizi X
ToDictionary Dictionary<TKey,TValue> X
ToList IList<T> X
ToLookup ILookup<TKey,TElement> X
Union IEnumerable<T> X
Where IEnumerable<T> X

LINQ to objects

"LINQ to Objects", doğrudan herhangi bir IEnumerable veya IEnumerable<T> koleksiyon ile LINQ sorgularının kullanımını ifade eder. LINQ kullanarak , Arrayveya Dictionary<TKey,TValue>gibi List<T>numaralandırılabilir koleksiyonları sorgulayabilirsiniz. Koleksiyon kullanıcı tanımlı veya .NET API tarafından döndürülen bir tür olabilir. LINQ yaklaşımında, ne almak istediğinizi açıklayan bildirim temelli kod yazarsınız. LINQ to Objects, LINQ ile programlamaya harika bir giriş sağlar.

LINQ sorguları, geleneksel foreach döngülere göre üç temel avantaj sunar:

  • Özellikle birden çok koşul filtrelendiğinde daha kısa ve okunabilirdir.
  • En az uygulama koduyla güçlü filtreleme, sıralama ve gruplandırma özellikleri sağlar.
  • Bunlar çok az değişiklikle veya hiç değişiklik yapılmadan diğer veri kaynaklarına taşınabilir.

Veriler üzerinde gerçekleştirmek istediğiniz işlem ne kadar karmaşık olursa, geleneksel yineleme teknikleri yerine LINQ kullanarak o kadar avantajlı olursunuz.

Bellekte sorgunun sonuçlarını depolama

Sorgu temelde verileri alma ve düzenleme yönergeleri kümesidir. Sonuçtaki sonraki her öğe istendiği için sorgular gevşek olarak yürütülür. Sonuçları yinelemek için kullandığınızda foreach , öğelere erişildikçe döndürülür. Bir sorguyu değerlendirmek ve döngü yürütmeden foreach sonuçlarını depolamak için sorgu değişkeninde aşağıdaki yöntemlerden birini çağırmak gerekir:

Aşağıdaki örnekte gösterildiği gibi sorgu sonuçlarını depolarken döndürülen koleksiyon nesnesini yeni bir değişkene atamanız gerekir:

List<int> numbers = [1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20];

IEnumerable<int> queryFactorsOfFour =
    from num in numbers
    where num % 4 == 0
    select num;

// Store the results in a new variable
// without executing a foreach loop.
var factorsofFourList = queryFactorsOfFour.ToList();

// Read and write from the newly created list to demonstrate that it holds data.
Console.WriteLine(factorsofFourList[2]);
factorsofFourList[2] = 0;
Console.WriteLine(factorsofFourList[2]);

Ayrıca bkz.