Dasar-dasar ekspresi kueri
Artikel ini memperkenalkan konsep dasar yang terkait dengan ekspresi kueri di C#.
Apa itu kueri dan apa yang dilakukannya?
Kueri adalah serangkaian instruksi yang menjelaskan data apa yang harus diambil dari sumber data (atau sumber) tertentu dan bentuk dan organisasi apa yang harus dimiliki data yang dikembalikan. Kueri berbeda dengan 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:
Ambil subset elemen untuk menghasilkan urutan baru tanpa memodifikasi elemen individual. Kueri kemudian dapat mengurutkan atau mengelompokkan urutan yang dikembalikan dengan berbagai cara, seperti yang diperlihatkan dalam contoh berikut (asumsikan
scores
adalahint[]
):IEnumerable<int> highScoresQuery = from score in scores where score > 80 orderby score descending select score;
Ambil urutan elemen seperti pada contoh sebelumnya tetapi ubah ke 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
kestring
. Perhatikan jenis baruhighScoresQuery
.IEnumerable<string> highScoresQuery2 = from score in scores where score > 80 orderby score descending select $"The score is {score}";
Ambil 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 melakukan iterasi atas 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 klausa 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 dimulai dengan klausa dari dan harus diakhiri dengan klausa pemilihan atau pengelompokan . Antara klausul from
pertama dan klausul select
atau group
terakhir, dapat berisi satu atau beberapa klausul opsional berikut: di mana, urutkan berdasarkan, gabung, biarkan dan bahkan klausul lainnya dari. Anda juga dapat menggunakan kata kunci into
untuk mengaktifkan hasil klausa join
atau group
untuk berfungsi sebagai sumber untuk klausa kueri lainnya dalam ekspresi kueri yang sama.
Variabel kueri
Di LINQ, variabel kueri adalah variabel apa pun yang menyimpan kueri foreach
atau panggilan langsung ke metode IEnumerator.MoveNext().
Nota
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 klausa pemfilteran, satu klausa pengurutan, dan tidak ada transformasi elemen sumber. Klausa 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 . Variabel kueri tidak menyimpan data hasil aktual, yang diproduksi dalam perulangan foreach
. Dan ketika pernyataan foreach
dijalankan, hasil kueri tidak dikembalikan melalui variabel kueri scoreQuery
. Sebaliknya, mereka dikembalikan melalui variabel iterasi testScore
. Variabel scoreQuery
dapat diulang dalam perulangan foreach
kedua. Ini menghasilkan hasil yang sama selama tidak ada yang dimodifikasi, baik itu maupun sumber data.
Variabel kueri mungkin menyimpan kueri yang dinyatakan dalam sintaks kueri atau sintaks metode, atau kombinasi keduanya. Dalam contoh berikut, queryMajorCities
dan queryMajorCities2
adalah 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 > 30_000_000
select city;
// Execute the query to produce the results
foreach (City city in queryMajorCities)
{
Console.WriteLine(city);
}
// Output:
// City { Name = Tokyo, Population = 37833000 }
// City { Name = Delhi, Population = 30290000 }
// Method-based syntax
IEnumerable<City> queryMajorCities2 = cities.Where(c => c.Population > 30_000_000);
// Execute the query to produce the results
foreach (City city in queryMajorCities2)
{
Console.WriteLine(city);
}
// Output:
// City { Name = Tokyo, Population = 37833000 }
// City { Name = Delhi, Population = 30290000 }
Di sisi lain, dua contoh berikut menunjukkan variabel yang bukan variabel kueri 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();
Pengetikan eksplisit dan implisit variabel kueri
Dokumentasi ini biasanya menyediakan jenis eksplisit variabel kueri untuk memperlihatkan hubungan jenis antara variabel kueri dan klausa pilih. Namun, Anda juga dapat menggunakan kata kunci var
var queryCities =
from city in cities
where city.Population > 100000
select city;
Dalam contoh sebelumnya, penggunaan var bersifat opsional.
queryCities
adalah IEnumerable<City>
baik secara implisit maupun eksplisit.
Memulai ekspresi kueri
Ekspresi kueri harus dimulai dengan klausa from
. Ini menentukan sumber data bersama dengan variabel rentang. Variabel rentang mewakili setiap elemen berturut-turut dalam urutan sumber saat urutan sumber sedang dilalui. Variabel rentang sangat ditik berdasarkan jenis elemen dalam sumber data. Dalam contoh berikut, karena countries
adalah array objek Country
, variabel rentang juga di ketikkan sebagai Country
. Karena variabel rentang ditik dengan kuat, Anda dapat menggunakan operator titik untuk mengakses anggota jenis yang tersedia.
IEnumerable<Country> countryAreaQuery =
from country in countries
where country.Area > 20 //sq km
select country;
Variabel rentang berada dalam cakupan hingga kueri keluar, baik dengan titik koma atau dengan klausa kelanjutan .
Ekspresi kueri mungkin berisi beberapa klausa from
. Gunakan lebih banyak klausa from
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 setiap Country
, gunakan dua klausa from
seperti yang diperlihatkan di sini:
IEnumerable<City> cityQuery =
from country in countries
from city in country.Cities
where city.Population > 10000
select city;
Untuk informasi selengkapnya, lihat dari klausa.
Mengakhiri ekspresi kueri
Ekspresi kueri harus diakhir dengan klausa group
atau klausa select
.
Klausa kelompok
Gunakan klausa group
untuk menghasilkan urutan grup yang diatur oleh kunci yang Anda tentukan. Kuncinya bisa berupa jenis data apa pun. Misalnya, kueri berikut membuat urutan grup yang berisi satu atau beberapa objek Country
dan kuncinya adalah jenis char
dengan nilai menjadi huruf pertama nama negara.
var queryCountryGroups =
from country in countries
group country by country.Name[0];
Untuk informasi selengkapnya tentang pengelompokan, lihat klausa grup .
pilih klausa
Gunakan klausa select
untuk menghasilkan semua jenis urutan lainnya. Klausa 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
. Klausa 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;
Klausa select
dapat digunakan untuk mengubah data sumber menjadi urutan jenis baru. Transformasi ini juga diberi nama proyeksi . Dalam contoh berikut, klausa select
memproyeksikan urutan jenis anonim yang hanya berisi subset kolom dari elemen asal. 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 klausa select
dapat digunakan untuk mengubah data sumber, lihat memilih klausa.
Kelanjutan dengan ke
Anda dapat menggunakan kata kunci into
dalam klausa select
atau group
untuk membuat pengidentifikasi sementara yang menyimpan kueri. Gunakan klausa into
saat Anda harus melakukan operasi kueri tambahan pada kueri setelah operasi pengelompokan atau seleksi. Dalam contoh berikut, countries
dikelompokkan sesuai dengan populasi dalam kisaran 10 juta. Setelah grup ini dibuat, klausa tambahan memfilter beberapa grup, kemudian 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 / 1_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 selengkapnya, lihat into
.
Memfilter, mengurutkan, dan bergabung
Antara klausa from
awal, dan klausa select
akhir atau group
, semua klausa lainnya (where
, join
, orderby
, from
, let
) bersifat opsional. Salah satu klausa opsional mungkin digunakan nol kali atau beberapa kali dalam isi kueri.
Klausa di mana
Gunakan klausa where
untuk memfilter elemen dari data sumber berdasarkan satu atau beberapa ekspresi predikat. Klausa where
dalam contoh berikut memiliki satu predikat dengan dua kondisi.
IEnumerable<City> queryCityPop =
from city in cities
where city.Population is < 15_000_000 and > 10_000_000
select city;
Untuk informasi selengkapnya, lihat tempat klausa.
Klausa orderby
Gunakan klausa orderby
untuk mengurutkan hasil dalam urutan naik atau turun. Anda juga dapat menentukan urutan pengurutan sekunder. Contoh berikut melakukan pengurutan utama pada objek country
dengan menggunakan properti Area
. Kemudian melakukan pengurutan sekunder dengan menggunakan properti Population
.
IEnumerable<Country> querySortedCountries =
from country in countries
orderby country.Area, country.Population descending
select country;
Kata kunci ascending
bersifat opsional; ini adalah urutan pengurutan default jika tidak ada urutan yang ditentukan. Untuk informasi selengkapnya, lihat klausul urutan .
Klausa gabungan
Gunakan klausa 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 pernyataan select
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
-nya cocok dengan salah satu kategori dalam array string categories
. Produk yang Category
nya tidak cocok dengan string apa pun di categories
difilter. Pernyataan select
memproyeksikan jenis baru yang propertinya diambil dari cat
dan prod
.
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 dengan menggunakan kata kunci into
. Untuk informasi selengkapnya, lihat klausa gabungan .
Klausa let
Gunakan klausa let
untuk menyimpan hasil ekspresi, seperti panggilan metode, dalam variabel rentang baru. Dalam contoh berikut, variabel rentang firstName
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 biarkan klausa.
Subkueri dalam ekspresi kueri
Klausa kueri mungkin berisi ekspresi kueri, yang terkadang disebut sebagai subkueri . Setiap subkueri dimulai dengan klausa from
sendiri yang tidak selalu menunjuk ke sumber data yang sama dalam klausa from
pertama. 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 Lakukan subkueri pada operasi pengelompokan.
Lihat juga
- Kueri kata kunci (LINQ)
- Gambaran Umum Operator Kueri standar