Bagikan melalui


Dasar-dasar ekspresi kueri

Artikel ini memperkenalkan konsep dasar yang terkait dengan ekspresi kueri di C#.

Apa itu kueri dan apa fungsinya?

Kueri adalah sekumpulan instruksi yang menjelaskan data apa yang akan diambil dari sumber data (atau sumber) tertentu dan bentuk serta organisasi apa yang harus dimiliki data yang dikembalikan. Kueri berbeda dari hasil yang dihasilkannya.

Umumnya, data sumber diatur secara logis sebagai urutan elemen dari jenis yang sama. Misalnya, tabel database SQL berisi urutan baris. Dalam file XML, ada "urutan" elemen XML (meskipun elemen XML diatur secara hierarkis dalam struktur pohon). Koleksi dalam memori berisi urutan objek.

Dari sudut pandang aplikasi, jenis dan struktur tertentu dari data sumber asli tidak penting. Aplikasi selalu melihat data sumber sebagai kumpulan IEnumerable<T> atau IQueryable<T>. Misalnya, di LINQ ke XML, data sumber dibuat terlihat sebagai IEnumerable<XElement>.

Mengingat urutan sumber ini, kueri mungkin melakukan salah satu dari tiga hal:

  • Mengambil subset elemen untuk menghasilkan urutan baru tanpa mengubah elemen individual. Kueri kemudian dapat mengurutkan atau mengelompokkan urutan yang dikembalikan dengan berbagai cara, seperti yang ditunjukkan dalam contoh berikut (asumsikan scores adalah int[]):

    IEnumerable<int> highScoresQuery =
        from score in scores
        where score > 80
        orderby score descending
        select score;
    
  • Mengambil urutan elemen seperti pada contoh sebelumnya tetapi mengubahnya menjadi jenis objek baru. Misalnya, kueri mungkin hanya mengambil nama keluarga dari rekaman pelanggan tertentu di sumber data. Atau mungkin mengambil rekaman lengkap lalu menggunakannya untuk membangun jenis objek dalam memori lain atau bahkan data XML sebelum menghasilkan urutan hasil akhir. Contoh berikut menunjukkan proyeksi dari int ke string. Perhatikan jenis baru highScoresQuery.

    IEnumerable<string> highScoresQuery2 =
        from score in scores
        where score > 80
        orderby score descending
        select $"The score is {score}";
    
  • Mengambil nilai singleton tentang data sumber, seperti:

    • Jumlah elemen yang cocok dengan kondisi tertentu.

    • Elemen yang memiliki nilai terbesar atau paling sedikit.

    • Elemen pertama yang cocok dengan kondisi, atau jumlah nilai tertentu dalam sekumpulan elemen tertentu. Misalnya, kueri berikut mengembalikan jumlah skor yang lebih besar dari 80 dari array bilangan bulat scores:

      var highScoreCount = (
          from score in scores
          where score > 80
          select score
      ).Count();
      

      Dalam contoh sebelumnya, perhatikan penggunaan tanda kurung di sekitar ekspresi kueri sebelum panggilan ke metode Enumerable.Count. Anda juga dapat menggunakan variabel baru untuk menyimpan hasil konkret.

      IEnumerable<int> highScoresQuery3 =
          from score in scores
          where score > 80
          select score;
      
      var scoreCount = highScoresQuery3.Count();
      

Dalam contoh sebelumnya, kueri dijalankan dalam panggilan ke Count, karena Count harus mengulangi hasil untuk menentukan jumlah elemen yang dikembalikan oleh highScoresQuery.

Apa itu ekspresi kueri?

Ekspresi kueri adalah kueri yang dinyatakan dalam sintaks kueri. Ekspresi kueri adalah konstruksi bahasa kelas satu. Ini sama seperti ekspresi lain dan dapat digunakan dalam konteks apa pun di mana ekspresi C# valid. Ekspresi kueri terdiri dari sekumpulan klausul yang ditulis dalam sintaks deklaratif yang mirip dengan SQL atau XQuery. Setiap klausa pada gilirannya berisi satu atau beberapa ekspresi C#, dan ekspresi ini mungkin berupa ekspresi kueri atau berisi ekspresi kueri.

Ekspresi kueri harus diawali dengan klausul from dan harus diakhiri dengan klausul select atau group. Antara klausa pertama from dan klausul atau group terakhirselect, klausul tersebut dapat berisi satu atau beberapa klausa opsional ini: di mana, orderby, gabungkan, biarkan dan bahkan yang lain dari klausa. Anda juga dapat menggunakan ke dalam kata kunci untuk mengaktifkan hasil join klausa atau group untuk berfungsi sebagai sumber untuk klausa kueri lainnya dalam ekspresi kueri yang sama.

Variabel kueri

Di LINQ, variabel kueri adalah variabel mana pun yang menyimpan kueri sebagai ganti kueri hasil. Lebih khusus lagi, variabel kueri selalu merupakan jenis enumerable yang menghasilkan urutan elemen ketika diulang dalam foreach pernyataan atau panggilan langsung ke metodenya IEnumerator.MoveNext() .

Catatan

Contoh dalam artikel ini menggunakan sumber data dan data sampel berikut.

record City(string Name, long Population);
record Country(string Name, double Area, long Population, List<City> Cities);
record Product(string Name, string Category);
static readonly City[] cities = [
    new City("Tokyo", 37_833_000),
    new City("Delhi", 30_290_000),
    new City("Shanghai", 27_110_000),
    new City("São Paulo", 22_043_000),
    new City("Mumbai", 20_412_000),
    new City("Beijing", 20_384_000),
    new City("Cairo", 18_772_000),
    new City("Dhaka", 17_598_000),
    new City("Osaka", 19_281_000),
    new City("New York-Newark", 18_604_000),
    new City("Karachi", 16_094_000),
    new City("Chongqing", 15_872_000),
    new City("Istanbul", 15_029_000),
    new City("Buenos Aires", 15_024_000),
    new City("Kolkata", 14_850_000),
    new City("Lagos", 14_368_000),
    new City("Kinshasa", 14_342_000),
    new City("Manila", 13_923_000),
    new City("Rio de Janeiro", 13_374_000),
    new City("Tianjin", 13_215_000)
];

static readonly Country[] countries = [
    new Country ("Vatican City", 0.44, 526, [new City("Vatican City", 826)]),
    new Country ("Monaco", 2.02, 38_000, [new City("Monte Carlo", 38_000)]),
    new Country ("Nauru", 21, 10_900, [new City("Yaren", 1_100)]),
    new Country ("Tuvalu", 26, 11_600, [new City("Funafuti", 6_200)]),
    new Country ("San Marino", 61, 33_900, [new City("San Marino", 4_500)]),
    new Country ("Liechtenstein", 160, 38_000, [new City("Vaduz", 5_200)]),
    new Country ("Marshall Islands", 181, 58_000, [new City("Majuro", 28_000)]),
    new Country ("Saint Kitts & Nevis", 261, 53_000, [new City("Basseterre", 13_000)])
];

Contoh kode berikut menunjukkan ekspresi kueri sederhana dengan satu sumber data, satu klausul pemfilteran, satu klausul pengurutan, dan tidak ada transformasi elemen sumber. Klausul select mengakhiri kueri.

// Data source.
int[] scores = [90, 71, 82, 93, 75, 82];

// Query Expression.
IEnumerable<int> scoreQuery = //query variable
    from score in scores //required
    where score > 80 // optional
    orderby score descending // optional
    select score; //must end with select or group

// Execute the query to produce the results
foreach (var testScore in scoreQuery)
{
    Console.WriteLine(testScore);
}

// Output: 93 90 82 82

Dalam contoh sebelumnya, scoreQuery adalah variabel kueri, yang terkadang disebut sebagai kueri saja. Variabel kueri tidak menyimpan data hasil aktual, yang diproduksi dalam perulangan foreach. Dan ketika foreach pernyataan dijalankan, hasil kueri tidak dikembalikan melalui variabel scoreQuerykueri . Sebaliknya, mereka dikembalikan melalui variabel testScoreiterasi . Variabel scoreQuery dapat diulang dalam perulangan foreach kedua. Ini menghasilkan hasil yang sama selama sumber data maupun sumber data tidak dimodifikasi.

Variabel kueri mungkin menyimpan kueri yang dinyatakan dalam sintaks kueri atau sintaks metode, atau kombinasi keduanya. Dalam contoh berikut, queryMajorCities dan queryMajorCities2 merupakan variabel kueri:

City[] cities = [
    new City("Tokyo", 37_833_000),
    new City("Delhi", 30_290_000),
    new City("Shanghai", 27_110_000),
    new City("São Paulo", 22_043_000)
];

//Query syntax
IEnumerable<City> queryMajorCities =
    from city in cities
    where city.Population > 100000
    select city;

// Execute the query to produce the results
foreach (City city in queryMajorCities)
{
    Console.WriteLine(city);
}

// Output:
// City { Population = 120000 }
// City { Population = 112000 }
// City { Population = 150340 }

// Method-based syntax
IEnumerable<City> queryMajorCities2 = cities.Where(c => c.Population > 100000);

Di sisi lain, dua contoh berikut menunjukkan variabel yang tidak mengkueri variabel meskipun masing-masing diinisialisasi dengan kueri. Mereka bukan variabel kueri karena menyimpan hasil:

var highestScore = (
    from score in scores
    select score
).Max();

// or split the expression
IEnumerable<int> scoreQuery =
    from score in scores
    select score;

var highScore = scoreQuery.Max();
// the following returns the same result
highScore = scores.Max();
var largeCitiesList = (
    from country in countries
    from city in country.Cities
    where city.Population > 10000
    select city
).ToList();

// or split the expression
IEnumerable<City> largeCitiesQuery =
    from country in countries
    from city in country.Cities
    where city.Population > 10000
    select city;
var largeCitiesList2 = largeCitiesQuery.ToList();

Jenis eksplisit dan implisit variabel kueri

Dokumentasi ini biasanya menyediakan jenis eksplisit variabel kueri untuk memperlihatkan hubungan jenis antara variabel kueri dan klausul select. Namun, Anda juga dapat menggunakan kata kunci var untuk menginstruksikan pengompilasi untuk menyimpulkan jenis variabel kueri (atau variabel lokal lainnya) pada waktu kompilasi. Misalnya, contoh kueri yang diperlihatkan sebelumnya dalam artikel ini juga dapat dinyatakan dengan menggunakan pengetikan implisit:

var queryCities =
    from city in cities
    where city.Population > 100000
    select city;

Dalam contoh sebelumnya, penggunaan var bersifat opsional. queryCitiesIEnumerable<City> adalah apakah secara implisit atau eksplisit ditik.

Memulai ekspresi kueri

Ekspresi kueri harus diawali dengan klausul from. Ini menentukan sumber data bersama dengan variabel rentang. Variabel rentang mewakili setiap elemen berturut-turut dalam urutan sumber karena urutan sumber sedang dilintasi. Variabel rentang sangat berjenis berdasarkan jenis elemen dalam sumber data. Dalam contoh berikut, karena countries merupakan array objek Country, variabel rentang juga memiliki jenis sebagai Country. Karena variabel rentang memiliki jenis yang kuat, Anda dapat menggunakan operator titik untuk mengakses anggota jenis yang tersedia.

IEnumerable<Country> countryAreaQuery =
    from country in countries
    where country.Area > 500000 //sq km
    select country;

Variabel rentang berada dalam cakupan hingga kueri keluar baik dengan titik koma atau dengan klausul continuation.

Ekspresi kueri mungkin berisi beberapa from klausa. Gunakan lebih from banyak klausa ketika setiap elemen dalam urutan sumber adalah koleksi itu sendiri atau berisi koleksi. Misalnya, asumsikan bahwa Anda memiliki kumpulan objek Country, yang masing-masing berisi kumpulan objek City bernama Cities. Untuk mengkueri objek City di masing-masing Country, gunakan dua klausul from seperti yang ditunjukkan di sini:

IEnumerable<City> cityQuery =
    from country in countries
    from city in country.Cities
    where city.Population > 10000
    select city;

(Untuk informasi selengkapnya, lihat klausul from.

Mengakhiri ekspresi kueri

Ekspresi kueri harus diakhiri dengan klausul group atau klausul select.

klausaul group

Gunakan klausul group untuk menghasilkan urutan grup yang diatur oleh kunci yang Anda tentukan. Kunci boleh berupa jenis data apa pun. Misalnya, kueri berikut membuat urutan grup yang berisi satu atau beberapa objek Country dan yang kuncinya adalah jenis char dengan nilai yang menjadi huruf pertama nama negara.

var queryCountryGroups =
    from country in countries
    group country by country.Name[0];

Untuk informasi selengkapnya tentang pengelompokan, lihat klausul group.

pilih klausa

Gunakan klausul select untuk menghasilkan semua jenis urutan lainnya. Klausul select sederhana hanya menghasilkan urutan dari jenis objek yang sama dengan objek yang terkandung dalam sumber data. Dalam contoh ini, sumber data berisi objek Country. Klausul orderby hanya mengurutkan elemen ke dalam urutan baru dan klausul select menghasilkan urutan objek Country yang diurutkan ulang.

IEnumerable<Country> sortedQuery =
    from country in countries
    orderby country.Area
    select country;

Klausul select dapat digunakan untuk mengubah data sumber menjadi urutan jenis baru. Transformasi ini juga bernama proyeksi. Dalam contoh berikut, select klausul memproyeksikan urutan jenis anonim yang hanya berisi subset bidang dalam elemen asli. Objek baru diinisialisasi dengan menggunakan penginisialisasi objek.

var queryNameAndPop =
    from country in countries
    select new
    {
        Name = country.Name,
        Pop = country.Population
    };

Jadi dalam contoh ini, var diperlukan karena kueri menghasilkan jenis anonim.

Untuk informasi selengkapnya tentang semua cara klausul select dapat digunakan untuk mengubah data sumber, lihat klausul select.

Kelanjutan dengan into

Anda bisa menggunakan kata kunci into dalam klausul select atau group untuk membuat pengidentifikasi sementara yang menyimpan kueri. into Gunakan klausa saat Anda harus melakukan operasi kueri tambahan pada kueri setelah pengelompokan atau memilih operasi. Dalam contoh berikut, countries dikelompokkan sesuai dengan populasi dalam kisaran 10 juta. Setelah grup ini dibuat, lebih banyak klausa memfilter beberapa grup, lalu untuk mengurutkan grup dalam urutan naik. Untuk melakukan operasi tambahan tersebut, kelanjutan yang diwakili oleh countryGroup diperlukan.

// percentileQuery is an IEnumerable<IGrouping<int, Country>>
var percentileQuery =
    from country in countries
    let percentile = (int)country.Population / 10_000_000
    group country by percentile into countryGroup
    where countryGroup.Key >= 20
    orderby countryGroup.Key
    select countryGroup;

// grouping is an IGrouping<int, Country>
foreach (var grouping in percentileQuery)
{
    Console.WriteLine(grouping.Key);
    foreach (var country in grouping)
    {
        Console.WriteLine(country.Name + ":" + country.Population);
    }
}

Untuk informasi lebih lanjut, lihat ke .

Memfilter, mengurutkan, dan bergabung

Antara klausul from awal, dan klausul select atau group akhir, semua klausul lainnya (where, join, orderby, from, let) bersifat opsional. Salah satu klausa opsional mungkin digunakan nol kali atau beberapa kali dalam isi kueri.

klausul where

Gunakan klausul where untuk memfilter elemen dari data sumber berdasarkan satu atau beberapa ekspresi predikat. Klausul where dalam contoh berikut memiliki satu predikat dengan dua kondisi.

IEnumerable<City> queryCityPop =
    from city in cities
    where city.Population is < 200000 and > 100000
    select city;

Untuk informasi selengkapnya, lihat klausul where.

klausul orderby

Gunakan klausul orderby untuk mengurutkan hasil dalam urutan naik atau turun. Anda juga dapat menentukan urutan pengurutan sekunder. Contoh berikut melakukan pengurutan utama pada objek country menggunakan properti Area. Kemudian ini melakukan pengurutan sekunder dengan menggunakan properti Population.

IEnumerable<Country> querySortedCountries =
    from country in countries
    orderby country.Area, country.Population descending
    select country;

Kata ascending kunci bersifat opsional; ini adalah urutan pengurutan default jika tidak ada urutan yang ditentukan. Untuk informasi selengkapnya, lihat klausul orderby.

klausul Join

Gunakan klausul join untuk mengaitkan dan/atau menggabungkan elemen dari satu sumber data dengan elemen dari sumber data lain berdasarkan perbandingan kesetaraan antara kunci yang ditentukan di setiap elemen. Di LINQ, operasi gabungan dilakukan pada urutan objek yang elemennya berbeda jenis. Setelah menggabungkan dua urutan, Anda harus menggunakan select pernyataan atau group untuk menentukan elemen mana yang akan disimpan dalam urutan output. Anda juga dapat menggunakan jenis anonim untuk menggabungkan properti dari setiap set elemen terkait ke dalam jenis baru untuk urutan output. Contoh berikut mengaitkan objek prod yang properti Category miliknya cocok dengan salah satu kategori dalam array string categories. Produk yang Category tidak cocok dengan string apa pun difilter categories . Pernyataan ini select memproyeksikan jenis baru yang propertinya diambil dari dan catprod.

var categoryQuery =
    from cat in categories
    join prod in products on cat equals prod.Category
    select new
    {
        Category = cat,
        Name = prod.Name
    };

Anda juga dapat melakukan gabungan grup dengan menyimpan hasil operasi join ke dalam variabel sementara menggunakan kata kunci into. Untuk informasi selengkapnya, lihat klausul join.

klausul let

Gunakan klausul let untuk menyimpan hasil ekspresi, seperti panggilan metode, dalam variabel rentang baru. Dalam contoh berikut, variabel firstName rentang menyimpan elemen pertama dari array string yang dikembalikan oleh Split.

string[] names = ["Svetlana Omelchenko", "Claire O'Donnell", "Sven Mortensen", "Cesar Garcia"];
IEnumerable<string> queryFirstNames =
    from name in names
    let firstName = name.Split(' ')[0]
    select firstName;

foreach (var s in queryFirstNames)
{
    Console.Write(s + " ");
}

//Output: Svetlana Claire Sven Cesar

Untuk informasi selengkapnya, lihat klausul let.

Subkueri dalam ekspresi kueri

Klausa kueri mungkin berisi ekspresi kueri, yang terkadang disebut sebagai subkueri. Setiap subkueri dimulai dengan klausanya sendiri from yang tidak selalu menunjuk ke sumber data yang sama dalam klausa pertama from . Misalnya, kueri berikut menunjukkan ekspresi kueri yang digunakan dalam pernyataan pilih untuk mengambil hasil operasi pengelompokan.

var queryGroupMax =
    from student in students
    group student by student.Year into studentGroup
    select new
    {
        Level = studentGroup.Key,
        HighestScore = (
            from student2 in studentGroup
            select student2.ExamScores.Average()
        ).Max()
    };

Untuk informasi selengkapnya, lihat Melakukan subkueri pada operasi pengelompokan.

Lihat juga