Ketika data berada di database, menyalin seluruh tabel ke memori hanya untuk menyaringnya bukan pilihan yang hemat. Entity Framework Core (EF Core) hadir sebagai provider LINQ untuk database: kueri LINQ yang kita tulis diterjemahkan menjadi SQL, lalu dieksekusi di server database. Pada bab ini, EF Core tidak dijalankan; pembahasan bersifat konseptual karena hasil kueri bergantung pada database yang dipakai.

Translasi Kueri menjadi SQL #

Bedanya dengan LINQ to Objects ada pada tipe kembalian. Kueri atas DbSet<Produk> menghasilkan IQueryable<T>, tipe yang menyimpan kueri sebagai expression tree — struktur data yang menggambarkan maksud kueri, bukan kode yang berjalan. Provider EF Core memeriksa pohon tersebut dan menyusun perintah SQL yang setara:

csharp
public class TokoContext : DbContext
{
    public DbSet<Produk> Produk => Set<Produk>();
}

// db adalah instance TokoContext yang sudah siap dipakai
var produkMahal = db.Produk
    .Where(p => p.Harga > 20000)
    .OrderBy(p => p.Nama)
    .Select(p => p.Nama);

foreach (string nama in produkMahal)
{
    Console.WriteLine(nama);
}

Bentuk SQL yang dibangkitkan kueri di atas kira-kira seperti berikut:

text Ilustrasi translasi SQL
SELECT [p].[Nama]
FROM [Produk] AS [p]
WHERE [p].[Harga] > 20000.0
ORDER BY [p].[Nama]

Perhatikan syarat dan pengurutan pindah utuh ke SQL, sehingga database yang menghitung, bukan aplikasi. Deferred execution juga berlaku di sini: SQL baru dikirim ketika foreach mengiterasi produkMahal, dan ToList() memicu pengiriman lebih awal. Karena kueri diterjemahkan pada waktu eksekusi, hasil cetak foreach bergantung pada isi database saat itu; bentuk SQL-nya pun dapat berbeda antara versi EF Core dan jenis database, misalnya SQL Server dengan PostgreSQL.

Batasan Translasi #

Tidak semua ekspresi C# memiliki padanan SQL. Predikat yang memanggil method buatan sendiri, misalnya p => TermasukPromo(p), tidak dapat diterjemahkan ke SQL. Pada kasus tersebut EF Core melempar exception saat kueri dieksekusi, bukan saat kompilasi, sehingga galatnya baru terlihat pada pengujian runtime. Gunakan fungsi yang didukung provider, dan periksa SQL yang dibangkitkan lewat logging selama pengembangan.