Bagikan melalui


Tutorial: Menulis kueri di C# menggunakan kueri terintegrasi bahasa (LINQ)

Dalam tutorial ini, Anda membuat sumber data dan menulis beberapa kueri LINQ. Anda dapat bereksperimen dengan ekspresi kueri dan melihat perbedaan dalam hasilnya. Panduan ini menunjukkan fitur bahasa C# yang digunakan untuk menulis ekspresi kueri LINQ. Anda dapat mengikuti dan membangun aplikasi dan bereksperimen dengan kueri sendiri. Artikel ini mengasumsikan Anda telah menginstal .NET SDK terbaru. Jika tidak, buka halaman .NET Downloads dan instal versi terbaru di komputer Anda.

Pertama, buat aplikasi. Dari konsol, ketik perintah berikut:

dotnet new console -o WalkthroughWritingLinqQueries

Atau, jika Anda lebih suka Visual Studio, buat aplikasi konsol baru bernama WalkthroughWritingLinqQueries.

Membuat sumber data dalam memori

Langkah pertama adalah membuat sumber data untuk kueri Anda. Sumber data untuk kueri adalah daftar sederhana rekaman Student. Setiap catatan Student memiliki nama depan, nama belakang, dan array bilangan bulat yang mewakili skor ujian mereka di kelas. Tambahkan file baru bernama students.cs, dan salin kode berikut ke dalam file tersebut:

namespace WalkthroughWritingLinqQueries;

public record Student(string First, string Last, int ID, int[] Scores);

Perhatikan karakteristik berikut:

  • Catatan Student terdiri dari properti yang diimplementasikan secara otomatis.
  • Setiap siswa dalam daftar diinisialisasi dengan konstruktor utama.
  • Deretan nilai untuk setiap siswa diinisialisasi dengan menggunakan konstruktor utama.

Selanjutnya, buat urutan rekaman Student yang berfungsi sebagai sumber kueri ini. Buka Program.cs, dan hapus kode boilerplate berikut:

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

Ganti dengan kode berikut yang membuat sebuah urutan rekaman Student:

using WalkthroughWritingLinqQueries;

// Create a data source by using a collection initializer.
IEnumerable<Student> students =
[
    new Student(First: "Svetlana", Last: "Omelchenko", ID: 111, Scores: [97, 92, 81, 60]),
    new Student(First: "Claire",   Last: "O'Donnell",  ID: 112, Scores: [75, 84, 91, 39]),
    new Student(First: "Sven",     Last: "Mortensen",  ID: 113, Scores: [88, 94, 65, 91]),
    new Student(First: "Cesar",    Last: "Garcia",     ID: 114, Scores: [97, 89, 85, 82]),
    new Student(First: "Debra",    Last: "Garcia",     ID: 115, Scores: [35, 72, 91, 70]),
    new Student(First: "Fadi",     Last: "Fakhouri",   ID: 116, Scores: [99, 86, 90, 94]),
    new Student(First: "Hanying",  Last: "Feng",       ID: 117, Scores: [93, 92, 80, 87]),
    new Student(First: "Hugo",     Last: "Garcia",     ID: 118, Scores: [92, 90, 83, 78]),

    new Student("Lance",   "Tucker",      119, [68, 79, 88, 92]),
    new Student("Terry",   "Adams",       120, [99, 82, 81, 79]),
    new Student("Eugene",  "Zabokritski", 121, [96, 85, 91, 60]),
    new Student("Michael", "Tucker",      122, [94, 92, 91, 91])
];
  • Urutan siswa diinisialisasi dengan ekspresi koleksi.
  • Jenis catatan Student memuat daftar statis semua siswa.
  • Beberapa panggilan konstruktor menggunakan argumen bernama untuk mengklarifikasi argumen mana yang cocok dengan parameter konstruktor mana.

Cobalah menambahkan beberapa siswa lagi dengan skor tes yang berbeda ke daftar siswa untuk lebih terbiasa dengan kode sejauh ini.

Membuat kueri

Selanjutnya, Anda membuat kueri pertama Anda. Kueri Anda, saat Anda menjalankannya, menghasilkan daftar semua siswa yang skornya pada tes pertama lebih besar dari 90. Karena seluruh objek Student dipilih, tipe kueri IEnumerable<Student>. Meskipun kode juga dapat menggunakan pengetikan implisit dengan menggunakan kata kunci var, pengetikan eksplisit digunakan untuk menggambarkan hasil dengan jelas. (Untuk informasi selengkapnya tentang var, lihat Variabel Lokal yang Di ketik secara Implisit.) Tambahkan kode berikut ke Program.cs, setelah kode yang membuat urutan siswa:

// Create the query.
// The first line could also be written as "var studentQuery ="
IEnumerable<Student> studentQuery =
    from student in students
    where student.Scores[0] > 90
    select student;

Variabel rentang kueri, student, berfungsi sebagai referensi untuk setiap Student di sumber, menyediakan akses anggota untuk setiap objek.

Jalankan kueri

Sekarang tulis perulangan foreach yang menyebabkan kueri dijalankan. Setiap elemen dalam urutan yang dikembalikan diakses melalui variabel iterasi dalam perulangan foreach. Jenis variabel ini Student, dan jenis variabel kueri kompatibel, IEnumerable<Student>. Setelah Anda menambahkan kode berikut, buat dan jalankan aplikasi untuk melihat hasilnya di jendela Konsol.

// Execute the query.
// var could be used here also.
foreach (Student student in studentQuery)
{
    Console.WriteLine($"{student.Last}, {student.First}");
}

// Output:
// Omelchenko, Svetlana
// Garcia, Cesar
// Fakhouri, Fadi
// Feng, Hanying
// Garcia, Hugo
// Adams, Terry
// Zabokritski, Eugene
// Tucker, Michael

Untuk menyempurnakan kueri lebih lanjut, Anda dapat menggabungkan beberapa kondisi Boolean dalam klausa where. Kode berikut menambahkan kondisi sehingga kueri mengembalikan siswa yang skor pertamanya lebih dari 90 dan skor terakhirnya kurang dari 80. Klausa where harus menyerupai kode berikut.

where student.Scores[0] > 90 && student.Scores[3] < 80  

Coba klausa where sebelumnya, atau eksperimen diri Anda dengan kondisi filter lainnya. Untuk informasi selengkapnya, lihat tempat klausa.

Mengurutkan hasil kueri

Lebih mudah untuk memindai hasilnya jika hasilnya dalam urutan tertentu. Anda dapat mengurutkan urutan yang dikembalikan oleh bidang apa pun yang dapat diakses di elemen sumber. Misalnya, klausul orderby berikut mengurutkan hasil dalam urutan alfabet dari A hingga Z sesuai dengan nama keluarga setiap siswa. Tambahkan klausa orderby berikut ke kueri Anda, tepat setelah pernyataan where dan sebelum pernyataan select:

orderby student.Last ascending

Sekarang ubah klausul orderby sehingga mengurutkan hasil dalam urutan terbalik sesuai dengan skor pada pengujian pertama, dari skor tertinggi menjadi skor terendah.

orderby student.Scores[0] descending

Ubah string format WriteLine sehingga Anda dapat melihat skornya:

Console.WriteLine($"{student.Last}, {student.First} {student.Scores[0]}");

Untuk informasi selengkapnya, lihat klausul urutan .

Mengelompokkan hasil

Pengelompokan adalah fitur yang kuat untuk ekspresi kueri. Kueri dengan klausul grup menghasilkan urutan grup, dan setiap grup itu sendiri berisi Key dan urutan yang terdiri dari semua anggota grup tersebut. Kueri baru berikut mengelompokkan siswa dengan menggunakan huruf pertama nama keluarga mereka sebagai kunci.

IEnumerable<IGrouping<char, Student>> studentQuery =
    from student in students
    group student by student.Last[0];

Jenis kueri diubah. Sekarang menghasilkan urutan grup yang memiliki jenis char sebagai kunci, dan urutan objek Student. Kode dalam perulangan eksekusi foreach juga harus berubah:

foreach (IGrouping<char, Student> studentGroup in studentQuery)
{
    Console.WriteLine(studentGroup.Key);
    foreach (Student student in studentGroup)
    {
        Console.WriteLine($"   {student.Last}, {student.First}");
    }
}
// Output:
// O
//   Omelchenko, Svetlana
//   O'Donnell, Claire
// M
//   Mortensen, Sven
// G
//   Garcia, Cesar
//   Garcia, Debra
//   Garcia, Hugo
// F
//   Fakhouri, Fadi
//   Feng, Hanying
// T
//   Tucker, Lance
//   Tucker, Michael
// A
//   Adams, Terry
// Z
//   Zabokritski, Eugene

Jalankan aplikasi dan lihat hasilnya di jendela Konsol. Untuk informasi selengkapnya, lihat klausa grup .

Pengkodean eksplisit dari IEnumerables ke IGroupings dapat dengan cepat menjadi melelahkan. Tulis kueri yang sama dan perulangan foreach dengan lebih mudah menggunakan var. Kata kunci var tidak mengubah jenis objek Anda; itu hanya menginstruksikan pengkompilasi untuk menyimpulkan jenis. Ubah jenis studentQuery dan variabel iterasi group menjadi var dan jalankan ulang kueri. Dalam perulangan foreach bagian dalam, variabel iterasi masih di ketik sebagai Student, dan kueri berfungsi seperti sebelumnya. Ubah variabel perulangan student menjadi var dan jalankan kueri lagi. Anda melihat bahwa Anda mendapatkan hasil yang sama persis.

IEnumerable<IGrouping<char, Student>> studentQuery =
    from student in students
    group student by student.Last[0];

foreach (IGrouping<char, Student> studentGroup in studentQuery)
{
    Console.WriteLine(studentGroup.Key);
    foreach (Student student in studentGroup)
    {
        Console.WriteLine($"   {student.Last}, {student.First}");
    }
}

Untuk informasi selengkapnya tentang var, lihat Variabel Lokal yang Di ketik secara Implisit.

Mengurutkan grup menurut nilai kuncinya

Grup dalam kueri sebelumnya tidak dalam urutan alfabet. Anda dapat memberikan klausa orderby setelah klausa group. Tetapi untuk menggunakan klausa orderby, Anda terlebih dahulu memerlukan pengidentifikasi yang berfungsi sebagai referensi ke grup yang dibuat oleh klausa group. Anda menyediakan pengidentifikasi dengan menggunakan kata kunci into, sebagai berikut:

var studentQuery4 =
    from student in students
    group student by student.Last[0] into studentGroup
    orderby studentGroup.Key
    select studentGroup;

foreach (var groupOfStudents in studentQuery4)
{
    Console.WriteLine(groupOfStudents.Key);
    foreach (var student in groupOfStudents)
    {
        Console.WriteLine($"   {student.Last}, {student.First}");
    }
}

// Output:
//A
//   Adams, Terry
//F
//   Fakhouri, Fadi
//   Feng, Hanying
//G
//   Garcia, Cesar
//   Garcia, Debra
//   Garcia, Hugo
//M
//   Mortensen, Sven
//O
//   Omelchenko, Svetlana
//   O'Donnell, Claire
//T
//   Tucker, Lance
//   Tucker, Michael
//Z
//   Zabokritski, Eugene

Jalankan kueri ini, dan grup sekarang diurutkan dalam urutan alfabet.

Anda dapat menggunakan kata kunci let untuk memperkenalkan pengidentifikasi untuk hasil dari ekspresi apa pun dalam ekspresi kueri. Pengidentifikasi ini bisa menjadi kenyamanan, seperti dalam contoh berikut. Ini juga dapat meningkatkan performa dengan menyimpan hasil ekspresi sehingga tidak perlu dihitung beberapa kali.

// This query returns those students whose
// first test score was higher than their
// average score.
var studentQuery5 =
    from student in students
    let totalScore = student.Scores[0] + student.Scores[1] +
        student.Scores[2] + student.Scores[3]
    where totalScore / 4 < student.Scores[0]
    select $"{student.Last}, {student.First}";

foreach (string s in studentQuery5)
{
    Console.WriteLine(s);
}

// Output:
// Omelchenko, Svetlana
// O'Donnell, Claire
// Mortensen, Sven
// Garcia, Cesar
// Fakhouri, Fadi
// Feng, Hanying
// Garcia, Hugo
// Adams, Terry
// Zabokritski, Eugene
// Tucker, Michael

Untuk informasi selengkapnya, lihat artikel tentang klausa let.

Menggunakan sintaks metode dalam ekspresi kueri

Seperti yang dijelaskan dalam sintaks kueri dan Sintaks Metode di LINQ, beberapa operasi kueri hanya dapat diekspresikan dengan menggunakan sintaks metode. Kode berikut menghitung skor total untuk setiap Student dalam urutan sumber, lalu memanggil metode Average() pada hasil kueri tersebut untuk menghitung skor rata-rata kelas.

var studentQuery =
    from student in students
    let totalScore = student.Scores[0] + student.Scores[1] +
        student.Scores[2] + student.Scores[3]
    select totalScore;

double averageScore = studentQuery.Average();
Console.WriteLine($"Class average score = {averageScore}");

// Output:
// Class average score = 334.166666666667

Untuk mengubah atau memproyeksikan dalam klausa pemilihan

Kueri umum untuk menghasilkan urutan yang elemennya berbeda dari elemen dalam urutan sumber. Hapus atau beri komentar pada kueri dan loop eksekusi sebelumnya, lalu gantikan dengan kode berikut. Kueri mengembalikan urutan string (tidak Students), dan fakta ini tercermin dalam perulangan foreach.

IEnumerable<string> studentQuery =
    from student in students
    where student.Last == "Garcia"
    select student.First;

Console.WriteLine("The Garcias in the class are:");
foreach (string s in studentQuery)
{
    Console.WriteLine(s);
}

// Output:
// The Garcias in the class are:
// Cesar
// Debra
// Hugo

Kode sebelumnya dalam panduan ini menunjukkan bahwa skor kelas rata-rata adalah sekitar 334. Untuk menghasilkan urutan Students yang skor totalnya lebih besar dari rata-rata kelas, bersama dengan Student ID, Anda dapat menggunakan tipe anonim dalam pernyataan select.

var aboveAverageQuery =
    from student in students
    let x = student.Scores[0] + student.Scores[1] +
        student.Scores[2] + student.Scores[3]
    where x > averageScore
    select new { id = student.ID, score = x };

foreach (var item in aboveAverageQuery)
{
    Console.WriteLine("Student ID: {0}, Score: {1}", item.id, item.score);
}

// Output:
// Student ID: 113, Score: 338
// Student ID: 114, Score: 353
// Student ID: 116, Score: 369
// Student ID: 117, Score: 352
// Student ID: 118, Score: 343
// Student ID: 120, Score: 341
// Student ID: 122, Score: 368