Menyimpan Transaksi Kasir ke Database SQLite dengan C# Console App
💾 Dari Struk Sementara ke Data Permanen
Ketika aplikasi kasir berhasil menampilkan daftar belanja di layar, rasanya mantap. Tapi, tanpa penyimpanan, data itu cuma sekadar mampir—seperti mantan yang numpang kuota. Supaya tidak berakhir sementara, kita butuh mekanisme penyimpanan transaksi ke database, agar semua pembelian bisa ditelusuri, dilaporkan, dan dianalisis.
Di sesi ini, kita menggunakan SQLite sebagai alat bantu. Bukan karena dia sempurna, tapi karena dia ringan, gratis, dan cocok untuk latihan lokal tanpa repot setup server. Tapi ingat, untuk sistem kasir produksi berskala besar, kamu wajib beralih ke engine database yang lebih tangguh seperti PostgreSQL, Firebird, MySQL, atau keluarga enterprise lainnya.
Yang akan kita bangun adalah alur penyimpanan transaksi berikut:
- ✅ Input data transaksi dan daftar belanja (simulasi)
- ✅ Validasi kelengkapan dan keakuratan data
- ✅ Menyimpan data ke tabel
Transaksi
danDetailTransaksi
Tujuannya sederhana: mengubah transaksi yang hanya tampil di layar menjadi data yang tercatat permanen di database. Karena kalau tidak dicatat, kamu tidak bisa bikin laporan, tidak bisa analisis, dan tidak bisa bilang, “Saya punya histori penjualan.”
🧱 Struktur Tabel Database
Sebelum menyimpan data, kita harus tahu mau disimpan ke mana. Di sini kita pakai dua tabel sederhana:
Transaksi
— untuk menyimpan informasi umum seperti tanggal, nama kasir, dan total hargaDetailTransaksi
— untuk menyimpan setiap item belanja dalam satu transaksi
CREATE TABLE Transaksi (
IdTransaksi INTEGER PRIMARY KEY AUTOINCREMENT,
Tanggal TEXT,
NamaKasir TEXT,
TotalHarga REAL
);
CREATE TABLE DetailTransaksi (
IdDetail INTEGER PRIMARY KEY AUTOINCREMENT,
IdTransaksi INTEGER,
NamaProduk TEXT,
Jumlah INTEGER,
HargaSatuan REAL,
FOREIGN KEY (IdTransaksi) REFERENCES Transaksi(IdTransaksi)
);
🧪 Validasi Input: Menjaga Data Tetap Waras
Sebelum data transaksi disimpan ke database, satu tahap yang tidak boleh dilewatkan adalah validasi input. Tujuannya bukan sekadar mencegah error teknis, tapi memastikan logika bisnis tetap jalan sesuai harapan. Bayangkan menyimpan jumlah barang minus, atau harga satuan nol—bukan cuma database-nya bingung, laporan keuangan pun bisa jadi absurd.
Validasi ini dijalankan langsung di Console App, sebagai penyaring awal sebelum data dimasukkan ke tabel. Setiap variabel dicek agar memenuhi syarat minimum: tidak kosong, tidak bertipe salah, dan tidak melanggar logika transaksi. Dengan cara ini, kita membatasi kesalahan sejak awal, bukan menunggu sistem crash dulu baru panik.
Berikut beberapa poin penting yang wajib divalidasi:
- Nama kasir: Wajib diisi. Tanpa nama, siapa yang bertanggung jawab atas transaksi?
- Daftar belanja: Harus ada item. Transaksi tanpa barang ibarat belanja tanpa pulang.
- Jumlah barang: Harus angka dan lebih dari nol. Tidak ada belanja yang “minjam stok” ke masa depan.
- Harga satuan: Tidak boleh negatif atau kosong. Diskon bukan berarti gratis apalagi rugi.
Kalau semua ini lolos, maka data bisa dianggap layak simpan. Tapi jika satu poin gagal, proses penyimpanan harus dibatalkan atau diarahkan ulang. Kita bukan sedang mengetik puisi—transaksi harus presisi, terukur, dan bisa ditelusuri.
🧑💻 Simulasi Input dan Validasi Data di Console App
Kita mulai dari simulasi input data transaksi lewat Console App. Tujuannya adalah mengumpulkan data yang akan disimpan ke database: nama kasir, daftar barang belanja, jumlah, dan harga satuan. Karena ini bukan aplikasi UI yang fancy, kita akan pakai metode
Console.ReadLine()
untuk semua input. Sederhana, tapi cukup untuk memastikan sistem bekerja.
Di sini validasi akan dilakukan langsung setelah input diterima. Kalau ada data yang kosong, salah format, atau tidak logis (misalnya harga minus), maka program akan memberikan peringatan dan meminta pengulangan input. Kita pastikan sebelum data masuk ke database, semuanya sudah bersih dan masuk akal.
Console.Write("Nama Kasir: ");
string namaKasir = Console.ReadLine();
if (string.IsNullOrWhiteSpace(namaKasir))
{
Console.WriteLine("❌ Nama kasir tidak boleh kosong!");
return;
}
List<DetailItem> daftarBelanja = new List<DetailItem>();
Console.Write("Jumlah produk yang ingin dimasukkan: ");
if (!int.TryParse(Console.ReadLine(), out int jumlahProduk) || jumlahProduk <= 0)
{
Console.WriteLine("❌ Jumlah produk harus berupa angka lebih dari 0.");
return;
}
for (int i = 0; i < jumlahProduk; i++)
{
Console.WriteLine($"\n📦 Produk ke-{i + 1}:");
Console.Write("Nama Produk: ");
string namaProduk = Console.ReadLine();
if (string.IsNullOrWhiteSpace(namaProduk))
{
Console.WriteLine("❌ Nama produk tidak boleh kosong!");
return;
}
Console.Write("Jumlah: ");
if (!int.TryParse(Console.ReadLine(), out int jumlah) || jumlah <= 0)
{
Console.WriteLine("❌ Jumlah harus angka dan lebih dari 0.");
return;
}
Console.Write("Harga Satuan: ");
if (!double.TryParse(Console.ReadLine(), out double harga) || harga <= 0)
{
Console.WriteLine("❌ Harga satuan harus angka dan lebih dari 0.");
return;
}
daftarBelanja.Add(new DetailItem
{
NamaProduk = namaProduk,
Jumlah = jumlah,
HargaSatuan = harga
});
}
📤 Output Console Hasil Uji
Nama Kasir: Astro Mart Jumlah produk yang ingin dimasukkan: 2 📦 Produk ke-1: Nama Produk: Kopi Latte Jumlah: 3 Harga Satuan: 12000 📦 Produk ke-2: Nama Produk: Roti Tawar Jumlah: 1 Harga Satuan: 8000 ✅ Data berhasil disimpan ke dalam list internal. Total Harga: 44000
Setelah seluruh input lolos validasi, kita siap melanjutkan ke proses perhitungan total harga dan insert ke database SQLite. Tapi sebelumnya, pastikan logika dan kelas bantu seperti
DetailItem
sudah kamu siapkan di project. Di tahap berikutnya, kita akan eksekusi penyimpanan ke tabel Transaksi
dan DetailTransaksi
.
🔗 Baca Juga: Encapsulation di C#: Jaga Data Seaman Dapur Restoran! – Pelajari bagaimana teknik encapsulation menjaga integritas data aplikasi kasir kamu, bahkan saat dapur lagi chaos.
💾 Menyimpan Data ke SQLite: Transaksi dan Detail
Setelah semua data belanja terkumpul dan lolos validasi, saatnya menyimpan ke database. Proses ini terdiri dari dua tahap: menyimpan header transaksi (tanggal, nama kasir, total harga), lalu menyimpan detail belanja untuk setiap produk. Kita akan gunakan
SQLiteCommand
untuk mengeksekusi perintah SQL secara langsung dari C#.
Sebelum eksekusi, pastikan koneksi ke database sudah terbuka dan class
DetailItem
tersedia di project kamu:
// Struktur class bantu untuk detail belanja
class DetailItem
{
public string NamaProduk { get; set; }
public int Jumlah { get; set; }
public double HargaSatuan { get; set; }
}
🔢 Hitung Total Harga Transaksi
// Hitung total harga
double totalHarga = 0;
foreach (var item in daftarBelanja)
{
totalHarga += item.Jumlah * item.HargaSatuan;
}
📥 Simpan Header Transaksi ke Database
using System.Data.SQLite;
string connString = "Data Source=kasir.db;";
using (SQLiteConnection conn = new SQLiteConnection(connString))
{
conn.Open();
// Simpan transaksi utama
string queryTransaksi = "INSERT INTO Transaksi (Tanggal, NamaKasir, TotalHarga) VALUES (@tanggal, @kasir, @total); SELECT last_insert_rowid();";
SQLiteCommand cmd = new SQLiteCommand(queryTransaksi, conn);
cmd.Parameters.AddWithValue("@tanggal", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
cmd.Parameters.AddWithValue("@kasir", namaKasir);
cmd.Parameters.AddWithValue("@total", totalHarga);
long idTransaksi = (long)cmd.ExecuteScalar(); // Dapatkan ID transaksi yang baru dibuat
🧾 Simpan Detail Produk per Item
// Simpan tiap detail produk
foreach (var item in daftarBelanja)
{
string queryDetail = "INSERT INTO DetailTransaksi (IdTransaksi, NamaProduk, Jumlah, HargaSatuan) VALUES (@id, @nama, @jumlah, @harga)";
SQLiteCommand cmdDetail = new SQLiteCommand(queryDetail, conn);
cmdDetail.Parameters.AddWithValue("@id", idTransaksi);
cmdDetail.Parameters.AddWithValue("@nama", item.NamaProduk);
cmdDetail.Parameters.AddWithValue("@jumlah", item.Jumlah);
cmdDetail.Parameters.AddWithValue("@harga", item.HargaSatuan);
cmdDetail.ExecuteNonQuery();
}
conn.Close();
}
Dengan kode ini, transaksi dicatat secara lengkap. Header menyimpan informasi utama, sedangkan detailnya mencatat tiap produk dan kuantitasnya. Praktis, ringkas, dan mudah untuk dikembangkan ke laporan atau ekspor data.
🔍 Verifikasi Hasil: SELECT dari Tabel SQLite
Setelah data transaksi dan detail belanja disimpan, kita bisa memastikan isinya lewat perintah
SELECT
. Di Console App, kita jalankan query ke dua tabel: Transaksi
dan DetailTransaksi
. Hasilnya akan ditampilkan sebagai teks biasa untuk memastikan data benar-benar tercatat.
// Buka koneksi ke SQLite
using (SQLiteConnection conn = new SQLiteConnection("Data Source=kasir.db;"))
{
conn.Open();
// Tampilkan isi tabel Transaksi
Console.WriteLine("=== TABEL TRANSAKSI ===");
string query1 = "SELECT * FROM Transaksi";
using (SQLiteCommand cmd1 = new SQLiteCommand(query1, conn))
using (SQLiteDataReader reader1 = cmd1.ExecuteReader())
{
while (reader1.Read())
{
Console.WriteLine($"ID: {reader1["IdTransaksi"]} | Tanggal: {reader1["Tanggal"]} | Kasir: {reader1["NamaKasir"]} | Total: {reader1["TotalHarga"]}");
}
}
// Tampilkan isi tabel DetailTransaksi
Console.WriteLine("\n=== DETAIL TRANSAKSI ===");
string query2 = "SELECT * FROM DetailTransaksi";
using (SQLiteCommand cmd2 = new SQLiteCommand(query2, conn))
using (SQLiteDataReader reader2 = cmd2.ExecuteReader())
{
while (reader2.Read())
{
Console.WriteLine($"Produk: {reader2["NamaProduk"]} | Jumlah: {reader2["Jumlah"]} | Harga: {reader2["HargaSatuan"]} | ID Transaksi: {reader2["IdTransaksi"]}");
}
}
conn.Close();
}
📤 Output Console Hasil SELECT
=== TABEL TRANSAKSI === ID: 1 | Tanggal: 2025-07-14 20:10:33 | Kasir: Astro Mart | Total: 44000 === DETAIL TRANSAKSI === Produk: Kopi Latte | Jumlah: 3 | Harga: 12000 | ID Transaksi: 1 Produk: Roti Tawar | Jumlah: 1 | Harga: 8000 | ID Transaksi: 1
Dari hasil SELECT di atas, kita bisa lihat data sudah masuk dengan rapi: satu transaksi utama, dua produk detail, dan semuanya terhubung lewat
IdTransaksi
. Ini jadi bukti bahwa proses insert bekerja, dan sistem kasir sederhana kamu sudah mencatat penjualan secara digital.
Melalui langkah-langkah di atas, kita berhasil merancang sistem kasir sederhana berbasis Console yang mencatat transaksi dengan struktur data yang jelas. Validasi input, penyimpanan ke database SQLite, dan pemisahan data utama dan detail menjadikan aplikasi ini tidak hanya fungsional, tapi juga siap dikembangkan lebih jauh.
Dengan pendekatan ini, kamu punya fondasi kuat untuk membangun sistem kasir UMKM atau versi latihan yang mendekati produksi. Fleksibel, modular, dan rapi—itulah prinsip di balik setiap potongan kode yang sudah kita lewati.
Di bagian selanjutnya, kita akan menambahkan fitur pencetakan struk transaksi: baik ke Console dengan layout 72mm, maupun versi Windows Forms untuk UI yang lebih menarik. Jangan lewatkan pembahasan berikutnya kalau kamu ingin naik level ke kasir digital profesional.
Terima kasih sudah membaca dan mengikuti tutorial ini. Sistem sederhana ini mungkin terlihat kecil, tapi pondasinya kuat—dan siap ditumbuhkan menjadi solusi yang lebih besar.
Melalui langkah-langkah di atas, kita berhasil membangun sistem kasir sederhana berbasis Console—mulai dari validasi input hingga penyimpanan data ke database SQLite. Struktur tabel yang rapi, pemisahan antara transaksi utama dan detail belanja, serta proses insert yang modular membuat aplikasi ini siap dikembangkan lebih lanjut.
Pendekatan seperti ini cocok untuk UMKM, proyek latihan, atau bahkan sistem internal toko kecil. Kode yang dijalankan bersih, logika bisnis jelas, dan data yang disimpan bisa ditelusuri. Dari sini, kamu bisa menambahkan fitur seperti pencetakan struk, rekap transaksi, atau visualisasi laporan.
Terima kasih sudah mengikuti pembahasan ini. Semoga konten ini bisa menjadi referensi nyata, bukan sekadar tutorial sekali baca.
🔮 Lanjut Belajar: Di artikel berikutnya, kita akan bahas cara mencetak struk transaksi 72mm langsung dari Console atau Windows Forms, lengkap dengan layout dan template yang bisa kamu pakai langsung.
🧾 Buka Artikel: Cetak Struk Thermal untuk Kasir Digital
🧾 Buka Artikel: Cetak Struk Thermal untuk Kasir Digital