
Foto oleh Pixabay via Pexels
LINQ (Language Integrated Query) adalah fitur C# yang memungkinkan query terhadap koleksi data ditulis dengan sintaks yang deklaratif dan ekspresif, mirip seperti menulis query SQL namun langsung terintegrasi dalam bahasa C# itu sendiri.
LINQ bekerja terhadap berbagai sumber data yang mengimplementasikan IEnumerable
Artikel ini membahas method LINQ paling sering dipakai seperti Where, Select, OrderBy, dan agregasi seperti Sum dan Count, serta perbedaan antara method syntax dan query syntax yang keduanya valid namun memiliki gaya penulisan berbeda.
Where untuk Memfilter Data
Where menyaring elemen berdasarkan kondisi lambda
Select untuk Transformasi Data
Select mengubah setiap elemen menjadi bentuk baru
OrderBy dan Agregasi dengan Sum, Count, Average
Kombinasi OrderBy dan fungsi agregat LINQ
Method Syntax vs Query Syntax
Dua gaya penulisan LINQ yang setara hasilnya
Deferred Execution pada LINQ dan Dampaknya terhadap Hasil Query
LINQ Where dieksekusi secara deferred, bukan saat dideklarasikan
Sebagian besar operator LINQ seperti Where, Select, dan OrderBy tidak langsung dieksekusi pada saat baris kode query dituliskan, melainkan baru benar-benar dijalankan ketika hasilnya diiterasi, misalnya melalui foreach atau dipaksa dengan method seperti ToList() dan ToArray(). Perilaku ini disebut deferred execution, dan pada contoh di atas menyebabkan angka yang ditambahkan ke list setelah query dideklarasikan tetap ikut masuk ke dalam hasil akhir karena query baru dievaluasi saat foreach berjalan.
Operator seperti Count(), Sum(), First(), atau ToList() justru bersifat immediate execution, artinya langsung mengeksekusi seluruh query pada saat dipanggil dan mengembalikan hasil akhirnya, bukan objek query yang masih bisa berubah. Memahami perbedaan ini penting untuk menghindari bug yang sulit dilacak, terutama ketika sebuah query LINQ disimpan dalam variabel lalu dipakai berulang kali di tempat yang berbeda sementara sumber datanya ikut berubah di antara pemakaian tersebut.
Jika hasil query dimaksudkan untuk dipakai sebagai snapshot data pada satu titik waktu tertentu dan tidak boleh berubah meskipun sumber datanya berubah setelahnya, solusinya adalah memaksa eksekusi segera dengan memanggil ToList() atau ToArray() tepat setelah query dideklarasikan, sehingga hasilnya disalin ke koleksi baru yang independen dari sumber data aslinya.
GroupBy dan OrderBy untuk Agregasi dan Pengurutan Data dengan LINQ
GroupBy mengelompokkan data, OrderByDescending mengurutkan dari nilai terbesar
Operator GroupBy pada LINQ mengelompokkan elemen koleksi berdasarkan key tertentu yang ditentukan melalui lambda expression, menghasilkan koleksi grup di mana setiap grup memiliki property Key sebagai nilai pengelompokan dan dapat diiterasi untuk mengakses seluruh elemen yang termasuk dalam grup tersebut. Pada contoh di atas, transaksi dikelompokkan berdasarkan Kategori, lalu setiap grup dijumlahkan nominalnya menggunakan Sum untuk menghasilkan rekap total per kategori.
OrderBy dan OrderByDescending dipakai untuk mengurutkan hasil query berdasarkan satu atau lebih kriteria, dengan OrderByDescending pada contoh di atas mengurutkan rekap dari total nominal terbesar ke terkecil. Jika dibutuhkan pengurutan berdasarkan lebih dari satu kriteria, method ThenBy atau ThenByDescending dapat dirangkai setelah OrderBy untuk menentukan kriteria pengurutan kedua ketika nilai kriteria pertama sama persis antar elemen.
Kombinasi GroupBy, Select, dan OrderBy seperti pada contoh di atas sangat umum dipakai untuk kebutuhan pelaporan dan dashboard, menggantikan query agregasi SQL seperti GROUP BY dan ORDER BY namun ditulis langsung dalam kode C# menggunakan koleksi in-memory. Perlu diperhatikan bahwa GroupBy pada LINQ to Objects memuat seluruh data ke memori terlebih dahulu, sehingga untuk dataset yang sangat besar, melakukan agregasi langsung pada level database query umumnya jauh lebih efisien. Ketika LINQ dipakai di atas Entity Framework misalnya, GroupBy dan OrderBy akan diterjemahkan menjadi perintah SQL yang dijalankan langsung oleh database, sehingga hanya hasil akhirnya saja yang dikirim kembali ke aplikasi, bukan seluruh baris data mentah.
Query Syntax vs Method Syntax pada LINQ
LINQ menyediakan dua gaya penulisan yang setara secara fungsional: query syntax yang mirip perintah SQL dengan kata kunci from, where, orderby, dan select, serta method syntax yang memanggil method ekstensi seperti Where() dan OrderBy() secara berantai menggunakan lambda expression. Keduanya dikompilasi menjadi kode yang pada dasarnya identik di belakang layar, sehingga tidak ada perbedaan performa yang berarti antara memilih salah satunya, murni soal gaya penulisan dan preferensi tim.
Query syntax cenderung lebih mudah dibaca untuk query dengan banyak klausa seperti join atau group yang kompleks karena strukturnya menyerupai bahasa query yang sudah dikenal, sementara method syntax lebih fleksibel karena bisa mengakses seluruh method ekstensi LINQ, termasuk yang tidak memiliki padanan kata kunci query seperti Count() atau FirstOrDefault(). Pemilihan gaya biasanya mengikuti konvensi tim atau kenyamanan pribadi, dan keduanya bahkan bisa dicampur dalam satu project yang sama.
Kesalahan Umum yang Sering Terjadi
Memanggil ToList() Berulang Kali pada Query yang Sama
Memanggil ToList() atau mengiterasi query LINQ yang sama berkali-kali akan mengeksekusi ulang seluruh logika query setiap saat karena sifatnya yang deferred execution, sebaiknya hasilnya disimpan sekali ke variabel jika akan dipakai berulang.
Lupa Query LINQ Bersifat Lazy, Bukan Langsung Dieksekusi
Mengubah koleksi sumber data setelah query LINQ didefinisikan namun sebelum diiterasi bisa menghasilkan hasil yang tidak terduga, karena query baru benar-benar dieksekusi saat iterasi terjadi, bukan saat baris query ditulis.
Menggunakan First() Tanpa Memeriksa Kemungkinan Koleksi Kosong
Method First() akan melempar InvalidOperationException jika koleksi kosong; FirstOrDefault() adalah alternatif yang lebih aman karena mengembalikan nilai default (biasanya null) alih-alih melempar exception.
Kapan Pendekatan Ini Tidak Cocok Dipakai
Method syntax lebih fleksibel dan mudah dirangkai dengan method LINQ lanjutan, menjadikannya pilihan yang lebih umum dipakai di kalangan developer C# untuk kebanyakan kasus sehari-hari.
Query syntax memberikan keterbacaan yang lebih baik untuk query kompleks dengan banyak join antar beberapa koleksi sumber data, mirip dengan menulis query SQL, namun tidak semua method LINQ memiliki padanan dalam query syntax, sehingga kadang perlu dikombinasikan dengan method syntax.
Ringkasan
LINQ memberikan cara yang deklaratif dan ekspresif untuk melakukan filter, transformasi, dan agregasi data terhadap berbagai sumber koleksi. Pahami sifat lazy execution-nya dan pilih antara method syntax atau query syntax sesuai kompleksitas query dan preferensi keterbacaan tim, karena keduanya menghasilkan hasil akhir yang identik.
Seri Belajar C# Fundamental:
← Sebelumnya: Collection Generic List Dictionary dan HashSet
→ Selanjutnya: Delegate Event dan Action Func di C#