Belajar C# - Data Access & Persistence
Series/Belajar C#/Episode 9
Episode 9 of 23

Belajar C# - Data Access & Persistence

Episode ini membahas akses data dengan Entity Framework Core: DbContext dan model, operasi CRUD, migrations dan relasi antar entitas, querying dengan LINQ dan raw SQL, serta provider database seperti SQL Server, PostgreSQL, dan SQLite.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Hampir semua aplikasi nyata menyimpan data secara permanen di database. Di ekosistem .NET, cara paling umum melakukannya adalah lewat Entity Framework Core — Object-Relational Mapper yang memetakan class C# menjadi tabel dan baris.

Dengan EF Core, kalian bekerja dengan database sebagai objek dan LINQ, bukan menulis SQL manual untuk setiap operasi. Meski begitu, memahami apa yang terjadi di balik layar tetap penting agar query tidak lambat di production.

Episode 9 ini membahas setup DbContext, operasi CRUD, migrations dan relationships, querying dengan LINQ dan raw SQL, serta pilihan provider database.

Entity Framework Core dan DbContext

Menginstall Paket

Mulai dengan menambah paket EF Core dan provider yang dipilih. Contoh berikut memakai SQLite agar mudah dicoba:

Menambah paket EF Core
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.Design

Perintah dotnet add package Microsoft.EntityFrameworkCore.Sqlite menambahkan provider SQLite. Untuk PostgreSQL atau SQL Server, ganti dengan Npgsql.EntityFrameworkCore.PostgreSQL atau Microsoft.EntityFrameworkCore.SqlServer.

Membuat DbContext dan Model

DbContext adalah unit kerja utama — objek yang merepresentasikan sesi dengan database:

DbContext dengan model
class TokoContext : DbContext
{
    public DbSet<Produk> Produk => Set<Produk>();
 
    protected override void OnConfiguring(DbContextOptionsBuilder options)
    {
        options.UseSqlite("Data Source=toko.db");
    }
}
 
class Produk
{
    public int Id { get; set; }
    public string Nama { get; set; } = "";
    public decimal Harga { get; set; }
}

Property DbSet<Produk> menjadi pintu akses ke tabel Produk. Convention EF Core mengubah class Produk menjadi tabel dengan kolom Id, Nama, dan Harga secara otomatis.

Operasi CRUD

Create, Read, Update, Delete

CRUD di EF Core dilakukan lewat method Add, Find, dan properti Remove, lalu disimpan dengan SaveChangesAsync:

Operasi CRUD lengkap
using var db = new TokoContext();
await db.Database.EnsureCreatedAsync();
 
var kopi = new Produk { Nama = "Kopi Gayo", Harga = 85_000m };
db.Produk.Add(kopi);
await db.SaveChangesAsync();
 
var hasil = await db.Produk.FindAsync(kopi.Id);
hasil!.Harga = 90_000m;
await db.SaveChangesAsync();
 
db.Produk.Remove(hasil);
await db.SaveChangesAsync();
Console.WriteLine("CRUD selesai.");

Perhatikan bahwa perubahan hanya diterapkan ke database saat SaveChangesAsync dipanggil. FindAsync membaca berdasarkan primary key dengan cache, dan Remove menandai baris untuk dihapus.

Migrations dan Relationships

Membuat dan Menerapkan Migrations

Migrations merekam perubahan skema database sebagai kode versioned, sehingga tim bisa menyinkronkan database tanpa manual SQL:

Membuat migration pertama
dotnet ef migrations add BuatTabelProduk
dotnet ef database update

Perintah dotnet ef migrations add BuatTabelProduk menghasilkan file migration, dan dotnet ef database update menerapkannya ke database. File migration harus di-commit ke Git agar semua developer punya riwayat skema yang sama.

Relasi Antar Entitas

Relasi dideklarasikan lewat navigation properties. Contoh relasi satu-ke-banyak:

Relasi satu-ke-banyak
class Kategori
{
    public int Id { get; set; }
    public string Nama { get; set; } = "";
    public List<Produk> Produk { get; set; } = new();
}
 
class Produk
{
    public int Id { get; set; }
    public string Nama { get; set; } = "";
    public int KategoriId { get; set; }
    public Kategori Kategori { get; set; } = null!;
}

EF Core mengubah KategoriId menjadi foreign key. Load data terkait dengan Include:

Mengambil relasi
var kategori = await db.Kategori
    .Include(k => k.Produk)
    .FirstAsync();
Console.WriteLine($"{kategori.Nama} punya {kategori.Produk.Count} produk");

Include melakukan join untuk menarik produk sekaligus, menghindari N+1 query.

Querying dengan LINQ dan Raw SQL

LINQ Query dan FromSqlRaw

Sebagian besar query ditulis dengan LINQ yang di-translate ke SQL. Untuk kasus kompleks, FromSqlRaw mengeksekusi SQL mentah:

LINQ dan raw SQL
var murah = await db.Produk
    .Where(p => p.Harga < 100_000m)
    .OrderByDescending(p => p.Harga)
    .ToListAsync();
 
var manual = await db.Produk
    .FromSqlRaw("SELECT * FROM Produk WHERE Harga < 100")
    .ToListAsync();
 
Console.WriteLine($"LINQ: {murah.Count}, raw SQL: {manual.Count}");

Gunakan LINQ sebagai default; FromSqlRaw untuk query yang sulit diekspresikan. Selalu pakai parameterized SQL melalui FromSqlInterpolated — jangan pernah menyambungkan string input pengguna, karena rawan SQL injection (dibahas di episode 13).

Provider Database Modern

Memilih Database

EF Core bersifat provider-agnostik: sebagian besar kode tetap sama, hanya package dan baris Use yang berubah:

  • SQL Server: pilihan utama untuk aplikasi enterprise Windows, lewat UseSqlServer.
  • PostgreSQL: open-source, fitur lengkap, populer di startup dan cloud-native.
  • SQLite: zero-configuration, sempurna untuk prototipe dan unit test.
Berganti provider PostgreSQL
options.UseNpgsql(
    "Host=localhost;Database=toko;Username=postgres;Password=rahasia");

Ganti satu baris Use dan package, dan model serta migrations kalian sebagian besar tetap berfungsi. Inilah kekuatan abstraksi EF Core.

Penutup

Inti yang harus dibawa pulang:

  • EF Core memetakan class menjadi tabel lewat DbContext.
  • Perubahan diterapkan ke database hanya saat SaveChangesAsync dipanggil.
  • Migrations membuat perubahan skema terdokumentasi dan versioned.
  • Include mencegah N+1 query saat menarik relasi.
  • Provider dapat diganti dengan mengubah satu baris konfigurasi.

Di episode 10 selanjutnya kita memastikan kualitas: testing dan quality assurance — unit testing dengan xUnit, mocking dengan Moq, integration testing dengan WebApplicationFactory, serta static analysis dan analyzer Roslyn.