LINQ (Language Integrated Query) menanamkan kemampuan query ke dalam bahasa Visual Basic, sehingga penyaringan dan pemilihan data ditulis sebagai bagian dari bahasanya sendiri. Topik ini membahas bentuk query yang paling mendasar, yaitu From, Where, dan Select, atas array maupun List(Of T) yang berisi kelas sederhana. Pembahasan juga mencakup deferensi eksekusi (deferred execution) dan perbandingannya dengan perulangan manual, sehingga keputusan kapan query lebih tepat digunakan dapat diambil dengan dasar yang jelas.
Penyaringan dengan perulangan manual#
Cara konvensional menyaring data adalah menelusuri koleksi dengan For Each, lalu mencetak atau menampung elemen yang lolos percabangan If. Pola ini bekerja dengan baik, tetapi logika penyaringan menyatu di dalam tubuh perulangan dan hasilnya perlu ditampung pada variabel tambahan. Program berikut menampilkan skor ujian yang mencapai 80 ke atas.
Module DemoLoop
Sub Main()
Dim skor() As Integer = {88, 72, 95, 64, 80}
For Each nilai As Integer In skor
If nilai >= 80 Then
Console.WriteLine(nilai)
End If
Next
End Sub
End Module88
95
80Perulangan tersebut membaca kelima elemen dan bercabang di dalam tubuhnya, sehingga maksud program, yaitu mengambil skor tinggi, baru terbaca setelah kedua struktur itu diikuti. Query LINQ menyatakan maksud yang sama dalam satu bentuk yang terpisah dari mekanisme penelusurannya.
Bentuk query From, Where, dan Select#
Query LINQ dalam VB tersusun atas klausa yang dibaca dari kiri ke kanan. From mendeklarasikan variabel rentang (range variable) yang mewakili satu elemen sumber pada setiap langkah, Where menyaring elemen dengan kondisi Boolean, dan Select menentukan bentuk setiap baris hasil. Bentuknya sebagai berikut.
' tidak-dijalankan
Dim tinggi = From n In nilai
Where n.Skor >= 80
Select n.NamaVariabel n hanya dikenali di dalam query, sedangkan tinggi menampung query yang sudah terbentuk. Baris hasilnya berupa deretan String karena Select n.Nama memproyeksikan setiap elemen ke properti Nama. Diagram berikut menggambarkan alurnya.
Klausa Where menerima kondisi yang hasilnya True atau False, sehingga elemen Budi dengan skor 72 dan Dewi dengan skor 64 tidak lolos. Klausa Select kemudian membentuk baris hasil tanpa mengubah sumbernya, dan daftar asal tetap berisi lima elemen setelah query selesai.
Query atas kelas sederhana#
Sumber query tidak terbatas pada bilangan dan teks. Kelas sederhana berikut digunakan di sepanjang modul ini sebagai data contoh, yaitu kelas NilaiUjian dengan dua properti otomatis, Nama bertipe String dan Skor bertipe Integer. Koleksinya berupa List(Of NilaiUjian) yang diisi sembilan siswa.
Module Program
Class NilaiUjian
Public Property Nama As String
Public Property Skor As Integer
End Class
Sub Main()
Dim nilai As New List(Of NilaiUjian) From {
New NilaiUjian With {.Nama = "Ali", .Skor = 88},
New NilaiUjian With {.Nama = "Budi", .Skor = 72},
New NilaiUjian With {.Nama = "Citra", .Skor = 95},
New NilaiUjian With {.Nama = "Dewi", .Skor = 64},
New NilaiUjian With {.Nama = "Eka", .Skor = 80},
New NilaiUjian With {.Nama = "Fajar", .Skor = 58},
New NilaiUjian With {.Nama = "Gita", .Skor = 90},
New NilaiUjian With {.Nama = "Hana", .Skor = 76},
New NilaiUjian With {.Nama = "Indra", .Skor = 88}
}
Dim tinggi = From n In nilai
Where n.Skor >= 80
Select n.Nama
For Each nama As String In tinggi
Console.WriteLine(nama)
Next
End Sub
End ModuleAli
Citra
Eka
Gita
IndraQuery tinggi menghasilkan lima nama, yaitu Ali, Citra, Eka, Gita, dan Indra, karena kelimanya memperoleh skor 80 ke atas. Proyeksi Select n.Nama membuat baris hasil bertipe String sehingga For Each langsung mencetak namanya. Apabila proyeksinya diganti menjadi Select n, baris hasilnya berupa objek NilaiUjian utuh dan properti lainnya tetap dapat dibaca.
Demo berikut menyimulasikan alur From, Where, dan Select atas daftar yang sama. Centang pilihan penyaringan dan proyeksinya, kemudian amati baris hasil beserta bentuk query-nya.
Kode sumber demo
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="utf-8">
<title>Demo From, Where, dan Select</title>
<style>
body { font-family: sans-serif; font-size: 14px; margin: 0; padding: 12px; color: #1f3554; }
.baksan { display: flex; gap: 16px; flex-wrap: wrap; }
table { border-collapse: collapse; }
td, th { border: 1px solid #9db4d6; padding: 3px 10px; text-align: left; }
th { background: #f6f8fc; }
.panel { flex: 1 1 240px; }
label { display: block; margin: 6px 0; }
code.query { display: block; background: #f6f8fc; border: 1px solid #9db4d6; padding: 8px; white-space: pre; font-size: 12.5px; }
.keluaran { background: #10141b; color: #d7e3f4; padding: 8px; min-height: 96px; white-space: pre; font-family: monospace; font-size: 12.5px; }
.judul { font-weight: bold; margin: 10px 0 4px; }
</style>
</head>
<body>
<div class="baksan">
<div>
<div class="judul">Data: nilai (List(Of NilaiUjian))</div>
<table id="tabel"></table>
</div>
<div class="panel">
<div class="judul">Pilihan query</div>
<label><input type="checkbox" id="saring" checked> Where n.Skor >= 80</label>
<label><input type="checkbox" id="proyeksi"> Select n.Nama</label>
<div class="judul">Query yang terbentuk</div>
<code class="query" id="query"></code>
<div class="judul">Keluaran</div>
<div class="keluaran" id="keluaran"></div>
</div>
</div>
<script>
var nilai = [
{ nama: "Ali", skor: 88 },
{ nama: "Budi", skor: 72 },
{ nama: "Citra", skor: 95 },
{ nama: "Dewi", skor: 64 },
{ nama: "Eka", skor: 80 },
{ nama: "Fajar", skor: 58 },
{ nama: "Gita", skor: 90 },
{ nama: "Hana", skor: 76 },
{ nama: "Indra", skor: 88 }
];
var tabel = document.getElementById("tabel");
var kepala = tabel.insertRow();
["Nama", "Skor"].forEach(function (t) {
var th = document.createElement("th");
th.textContent = t;
kepala.appendChild(th);
});
nilai.forEach(function (n) {
var baris = tabel.insertRow();
baris.insertCell().textContent = n.nama;
baris.insertCell().textContent = n.skor;
});
function jalankan() {
var saring = document.getElementById("saring").checked;
var proyeksi = document.getElementById("proyeksi").checked;
var kode = "Dim hasil = From n In nilai\n";
if (saring) { kode += " Where n.Skor >= 80\n"; }
kode += proyeksi ? " Select n.Nama" : " Select n";
document.getElementById("query").textContent = kode;
var hasil = nilai.slice();
if (saring) { hasil = hasil.filter(function (n) { return n.skor >= 80; }); }
if (proyeksi) {
hasil = hasil.map(function (n) { return n.nama; });
document.getElementById("keluaran").textContent = hasil.join("\n");
} else {
document.getElementById("keluaran").textContent =
hasil.map(function (n) { return n.nama + " " + n.skor; }).join("\n");
}
}
document.getElementById("saring").addEventListener("change", jalankan);
document.getElementById("proyeksi").addEventListener("change", jalankan);
jalankan();
</script>
</body>
</html>Deferensi eksekusi#
Variabel query menyimpan definisi, bukan hasil. Eksekusinya menunggu penelusuran, perilaku yang disebut deferensi eksekusi (deferred execution), dan setiap penelusuran membaca kondisi koleksi terkini. Program berikut menambahkan satu siswa setelah query didefinisikan.
Module DemoDeferensi
Class NilaiUjian
Public Property Nama As String
Public Property Skor As Integer
End Class
Sub Main()
Dim nilai As New List(Of NilaiUjian) From {
New NilaiUjian With {.Nama = "Ali", .Skor = 88},
New NilaiUjian With {.Nama = "Budi", .Skor = 72},
New NilaiUjian With {.Nama = "Citra", .Skor = 95},
New NilaiUjian With {.Nama = "Eka", .Skor = 80}
}
Dim tinggi = From n In nilai
Where n.Skor >= 80
Select n
Console.WriteLine($"Saat query didefinisikan: {tinggi.Count()}")
nilai.Add(New NilaiUjian With {.Nama = "Indra", .Skor = 88})
Console.WriteLine($"Setelah Indra ditambahkan: {tinggi.Count()}")
End Sub
End ModuleSaat query didefinisikan: 3
Setelah Indra ditambahkan: 4Count() mengeksekusi query pada saat dipanggil, sehingga hasil pertamanya adalah 3 karena baru tiga siswa yang skornya mencapai 80. Setelah Indra ditambahkan, penelusuran yang sama menghasilkan 4, artinya query menggunakan isi daftar yang terbaru dan bukan potret saat definisinya ditulis. Perilaku ini menguntungkan karena query tidak perlu didefinisikan ulang ketika datanya berubah.
Perbandingan dengan perulangan manual#
Kedua pendekatan menghasilkan program yang benar, dan perbedaannya terletak pada bentuk penulisannya. Tabel berikut merangkum pembeda utamanya.
| Aspek | Perulangan manual | Query LINQ |
|---|---|---|
| Tempat logika penyaringan | Percabangan If di dalam tubuh perulangan | Klausa Where yang berdiri sendiri |
| Pembentukan hasil | Variabel penampung yang dikelola sendiri | Select langsung menyatakan baris hasil |
| Alur bertahap | Bertingkat dan menyatu dengan mekanisme penelusuran | Setiap tahap menjadi klausa tersendiri |
| Tipe variabel rentang | Ditulis eksplisit pada For Each | Disimpulkan compiler dari tipe sumbernya |
Perulangan manual tetap tepat ketika setiap elemen membutuhkan perlakuan yang berbeda-beda, misalnya pencabangan bertingkat per elemen. Query lebih padat ketika alurnya berupa penyaringan dan proyeksi yang berurutan, karena tiap tahap terbaca sebagai satu klausa. Keduanya dapat dipadukan dalam satu program tanpa masalah.
Kesalahan umum#
Tiga kesalahan berikut berkait erat dengan perilaku query yang baru diperkenalkan. Pemahaman deferensi eksekusi menutup sebagian besar di antaranya.
- Mengira variabel query menyimpan salinan data. Data yang ditambahkan setelah query didefinisikan ikut terbaca pada penelusuran berikutnya, sebagaimana ditunjukkan pada bagian Deferensi eksekusi. Bila potret tetap diinginkan, panggil
ToListatauToArray. - Membandingkan tipe yang tidak cocok pada
Where. Kondisin.Nama >= 80membandingkanStringdenganIntegerdan ditolak compiler ketikaOption Strict Onaktif. Pastikan properti yang dibandingkan bertipe angka, misalnyan.Skor. - Menggunakan variabel rentang di luar query.
nhanya dikenali di dalam klausa yang mendeklarasikannya, sehingga penulisann.Skorsetelah query selesai ditolak compiler sebagai variabel yang tidak dideklarasikan.
Ringkasan#
- Query LINQ menyusun penyaringan dan proyeksi sebagai klausa, yaitu
Fromuntuk variabel rentang,Whereuntuk kondisi Boolean, danSelectuntuk bentuk baris hasil. - Sumber query dapat berupa array maupun
List(Of T)yang berisi kelas sederhana, dan tipe baris hasil mengikuti bentukSelect. - Eksekusi query menunggu penelusuran, sehingga hasilnya selalu menggunakan kondisi data terkini.
- Perulangan manual tetap digunakan untuk perlakuan per elemen yang bercabang, sedangkan query lebih padat untuk alur penyaringan berurutan.
Referensi#
- Introduction to LINQ in Visual Basic — Microsoft Learn — Pengenalan LINQ, penyedia data, dan bentuk query pada VB.
- Basic Query Operations — Microsoft Learn — Operasi dasar query, dari sumber data, penyaringan, sampai proyeksi.
- From Clause — Microsoft Learn — Deklarasi variabel rentang pada awal query.
- Where Clause — Microsoft Learn — Penyaringan elemen dengan kondisi Boolean.
- Select Clause — Microsoft Learn — Proyeksi hasil query ke bentuk yang diinginkan.