Local Database di Flutter dengan SQLite dan Floor: CRUD dan Migration

Lhuqita Fazry
Mobile Development Flutter SQLite Floor Local Database
Local Database di Flutter dengan SQLite dan Floor: CRUD dan Migration

Menentukan Pendekatan Local Database yang Tepat untuk Flutter

Saat membangun aplikasi Flutter yang membutuhkan penyimpanan data lokal, kita dihadapkan pada beberapa pilihan library. Masing-masing memiliki pendekatan dan trade-off yang berbeda. Opsi yang paling umum meliputi sqflite secara langsung, Floor ORM, Hive, dan drift (dulu dikenal sebagai moor).

sqflite memberikan kendali penuh atas query SQL mentah, tetapi kita harus menulis boilerplate untuk konversi antara Map<String, dynamic> dan objek Dart. Hive menawarkan performa sangat cepat untuk data key-value sederhana, namun tidak mendukung query relasional. drift sangat powerful untuk proyek berskala besar, tapi kurva belajarnya cukup tinggi.

Di tengah spektrum tersebut, Floor ORM hadir sebagai solusi yang seimbang. Floor memberikan type safety melalui code generation — kita cukup mendefinisikan entity dengan anotasi, dan kode untuk konversi data dihasilkan secara otomatis. Pola anotasi @Entity, @dao, dan @Database pada Floor sangat mirip dengan Room di Android native, sehingga terasa familiar bagi developer yang sudah pernah bekerja dengan platform Android.

Prinsip dasar SQLite tetap menjadi fondasi di sini: tabel menyimpan data dalam baris dan kolom, query SQL digunakan untuk mengambil data, dan transaksi menjaga konsistensi operasi read-write. Floor tidak menyembunyikan SQL, melainkan membungkusnya dalam lapisan yang lebih aman dan nyaman digunakan.

Untuk skenario CRUD dengan migasi terstruktur — seperti yang sering kita temui di aplikasi produksi — Floor menawarkan kombinasi kemudahan pengembangan dan ketangguhan yang sulit ditandingi oleh library lain di kategori yang sama.

Setup dan Konfigurasi Awal Floor di Proyek Flutter

Langkah pertama adalah menambahkan dependensi Floor ke file pubspec.yaml. Kita membutuhkan tiga package utama: floor sebagai library inti, sqflite sebagai driver SQLite, dan floor_generator beserta build_runner untuk proses code generation.

yamlyaml
dependencies:
  flutter:
    sdk: flutter
  floor: ^1.4.2
  sqflite: ^2.3.0

dev_dependencies:
  floor_generator: ^1.4.2
  build_runner: ^2.4.0

Setelah menjalankan flutter pub get, kita bisa mulai mendefinisikan entity pertama. Entity adalah representasi dari tabel di database. Floor menggunakan anotasi @Entity untuk menandai kelas Dart yang akan dijadikan tabel.

dartdart
import 'package:floor/floor.dart';

@Entity(tableName: 'item')
class Item {
  @primaryKey
  final int id;
  final String name;
  final String category;
  final int quantity;

  Item({
    required this.id,
    required this.name,
    required this.category,
    required this.quantity,
  });
}

Tahap selanjutnya adalah inisialisasi database di entry point aplikasi. Floor menghasilkan kelas $FloorAppDatabase setelah proses code generation. Kita panggil metode databaseBuilder() dengan nama file database dan versi, lalu tunggu hingga database siap digunakan.

dartdart
final database = await $FloorAppDatabase
    .databaseBuilder('app_database.db')
    .build();

Proses code generation dijalankan melalui perintah flutter pub run build_runner build. Floor akan membaca semua anotasi di proyek kita dan menghasilkan file *.g.dart yang berisi implementasi konkret dari DAO dan database. File hasil generate ini tidak perlu diedit manual — cukup dipanggil sesuai kebutuhan.

Mendefinisikan Entity, DAO, dan Database — Arsitektur di Balik Layar

Setelah setup awal selesai, kita perlu memahami tiga komponen arsitektural utama yang membentuk pola kerja Floor: Entity, DAO, dan Database.

Diagram arsitektur Floor ORM yang menunjukkan hubungan antara Entity, DAO, dan Database — Entity merepresentasikan tabel, DAO mengelola akses data, dan Database menjadi titik akses pusat ke SQLite

Gambar: Diagram arsitektur Floor ORM — Entity, DAO, dan Database — Sumber: [Floor SQLite Documentation](https://pinchbv.github.io/floor/architecture/)

Advanced Flutter State Management with BLoC
Mobile App • Intermediate

Advanced Flutter State Management with BLoC

Master advanced Flutter state management by building a production-ready applicat...

Daftar

Entity adalah representasi tabel. Selain anotasi @Entity, kita bisa menambahkan properti opsional seperti foreignKeys dan indices. Kolom yang tidak ingin disimpan bisa ditandai dengan @ignore. Floor secara otomatis memetakan field kelas Dart ke kolom SQLite berdasarkan nama, kecuali kita tentukan berbeda melalui anotasi @ColumnInfo(name: 'nama_kolom').

DAO (Data Access Object) adalah tempat kita mendefinisikan operasi database. Floor menyediakan anotasi praktis seperti @insert, @update, dan @delete, serta @Query untuk SQL mentah. Parameter query bisa di-bind menggunakan sintaks :namaParameter.

dartdart
@dao
abstract class ItemDao {
  @Query('SELECT * FROM item')
  Future<List<Item>> getAllItems();

  @Query('SELECT * FROM item WHERE category = :category')
  Future<List<Item>> getItemsByCategory(String category);

  @insert
  Future<void> insertItem(Item item);

  @update
  Future<void> updateItem(Item item);

  @delete
  Future<void> deleteItem(Item item);
}

Perhatikan bahwa DAO ditulis sebagai kelas abstrak. Floor akan menggenerasi implementasi konkretnya dalam file *.g.dart. Setiap kali kita memanggil dao.insertItem(item), Floor mengonversi objek Dart ke Map<String, dynamic>, lalu menjalankan query INSERT ke SQLite.

Database menggabungkan seluruh entity dan DAO dalam satu kelas. Anotasi @Database menerima daftar entity yang terdaftar, versi database, dan kelas DAO yang tersedia.

dartdart
import 'package:floor/floor.dart';
import 'package:sqflite/sqflite.dart' as sqflite;

@Database(version: 1, entities: [Item])
abstract class AppDatabase extends FloorDatabase {
  ItemDao get itemDao;
}

Kombinasi ketiga komponen ini menciptakan lapisan akses data yang aman tipe. Compiler akan mendeteksi kesalahan seperti nama kolom yang salah atau tipe data yang tidak cocok saat proses build, bukan saat runtime.

Implementasi CRUD Lengkap — Menulis dan Membaca Data

Dengan entity, DAO, dan database yang sudah terdefinisi, kita bisa langsung mengimplementasikan operasi CRUD. Flow kerja di Flutter dimulai dari UI, memanggil method DAO melalui repository atau BLoC, dan data disimpan atau dibaca dari SQLite.

Berikut contoh operasi insert dengan konfigurasi konflik. Floor memungkinkan kita menentukan @Insert(onConflict: OnConflictStrategy.replace) untuk menangani duplikasi primary key.

dartdart
Future<void> saveItem(ItemDao dao) async {
  final item = Item(
    id: 1,
    name: 'Laptop ThinkPad',
    category: 'Elektronik',
    quantity: 5,
  );

  await dao.insertItem(item);
  print('Item berhasil disimpan');
}

Untuk query dengan filter, kita gunakan @Query dengan parameter binding. Parameter di query SQL ditulis dengan awalan titik dua (:category), dan Floor secara otomatis menggantinya dengan nilai argumen method.

dartdart
Future<void> queryByCategory(ItemDao dao) async {
  final items = await dao.getItemsByCategory('Elektronik');

  for (final item in items) {
    print('${item.name}${item.quantity} pcs');
  }
}

Operasi update dan delete membutuhkan primary key yang stabil. Floor mengidentifikasi baris yang akan diubah berdasarkan nilai field yang ditandai @primaryKey. Jika kita ingin mengubah data, cukup buat objek baru dengan id yang sama, lalu panggil dao.updateItem(item).

dartdart
Future<void> updateAndDelete(ItemDao dao) async {
  final updated = Item(
    id: 1,
    name: 'Laptop ThinkPad X1',
    category: 'Elektronik',
    quantity: 3,
  );
  await dao.updateItem(updated);

  final toDelete = Item(
    id: 2,
    name: 'Monitor LG',
    category: 'Elektronik',
    quantity: 1,
  );
  await dao.deleteItem(toDelete);
}

Untuk menampilkan data di UI secara reaktif, Floor mendukung Flowable<T> yang berasal dari package rxdart. Flowable memungkinkan UI mendengarkan perubahan data dan memperbarui tampilan secara otomatis tanpa perlu memicu query ulang secara manual. Cocok digunakan bersama StreamBuilder untuk membangun antarmuka yang selalu sinkron dengan database.

Strategi Migrasi Database — Mengubah Skema Tanpa Kehilangan Data

Aplikasi terus berkembang, dan skema database pun perlu beradaptasi. Migrasi diperlukan ketika kita menambah kolom baru, mengubah tipe data, mengganti nama kolom, atau menghapus tabel yang tidak lagi digunakan.

Diagram sintaks ALTER TABLE di SQLite — perintah SQL yang digunakan untuk mengubah struktur tabel dalam migrasi database

Gambar: Diagram sintaks ALTER TABLE SQLite — Sumber: [SQLite](https://sqlite.org/syntaxdiagrams.html)

Floor menangani migrasi melalui parameter version di anotasi @Database dan callback migrations saat membangun database. Setiap perubahan versi membutuhkan kelas Migration yang menentukan SQL yang dijalankan untuk berpindah dari versi lama ke versi baru.

dartdart
@Database(version: 2, entities: [Item])
abstract class AppDatabase extends FloorDatabase {
  ItemDao get itemDao;
}
dartdart
final migration1to2 = Migration(1, 2, (database) async {
  await database.execute(
    'ALTER TABLE item ADD COLUMN description TEXT',
  );
});

final database = await $FloorAppDatabase
    .databaseBuilder('app_database.db')
    .addMigrations([migration1to2])
    .build();

Kode di atas mendefinisikan migrasi dari versi 1 ke versi 2. SQL ALTER TABLE menambahkan kolom description bertipe TEXT ke tabel item. Kolom baru ini akan bernilai NULL untuk baris yang sudah ada sebelumnya — data lama tetap utuh.

Best practice yang perlu diingat: selalu uji migrasi di environment development sebelum merilis ke production. Buat skenario di mana database lama sudah berisi data, lalu jalankan aplikasi versi baru dan verifikasi bahwa semua data lama masih bisa diakses dan kolom baru berfungsi dengan benar.

Floor juga menyediakan opsi fallbackToDestructiveMigration yang akan menghapus database lama dan membuat ulang dari awal. Opsi ini sangat berisiko untuk production karena semua data pengguna akan hilang. Gunakan hanya untuk tahap prototyping atau development internal.

Konsep local database ini adalah fondasi penting dalam membangun aplikasi Flutter yang offline-first dan responsif. Dengan Floor, kita mendapatkan type safety, kemudahan migrasi, dan pola arsitektur yang bersih — semua tanpa harus meninggalkan kekuatan SQL yang sudah kita kenal. Di program Flutter Development Bootcamp Rumah Coding, kita praktikkan langsung konsep ini dalam proyek nyata, mulai dari local database, state management, hingga deployment aplikasi Flutter secara end-to-end.

Kursus Terkait

TaskSync: Real-Time Collaborative Task Manager
Kursus Premium Mobile App

Advanced Flutter State Management with BLoC

Master advanced Flutter state management by building a production-ready application. This intermediate course uses a top-down, problem-driven approach, plunging you into real-world engineering challenges. You will learn to architect scalable applications, handle complex reactive states, manage multi-BLoC communication, synchronize real-time data, and implement optimistic UI updates using industry-standard BLoC patterns.

Proyek Akhir

TaskSync: Real-Time Collaborative Task Manager

  • Role-Based Authentication: Secure login and session management, dynamically reflecting user states across the entire application.
  • Real-Time Task Board: A Kanban-style board that instantly updates across all devices when any team member creates, moves, or deletes a task.
  • Advanced Search & Filtering: High-performance local search with event debouncing to prevent unnecessary API calls.
7 Weeks Intermediate
Lihat Detail Kursus
DailyQuest: Gamified Habit Tracker
Kursus Premium Mobile App

Flutter Mobile Development

Launch your mobile development journey with this immersive, project-based Flutter course. Designed specifically for beginners, this program takes you from coding fundamentals in Dart to deploying a fully functional mobile app. You will learn to craft beautiful, responsive UIs, handle global state management, and integrate cloud backends. By the end of the course, you will have built a real-world, cloud-synced application from scratch.

Proyek Akhir

DailyQuest: Gamified Habit Tracker

  • Secure Authentication: User registration and login functionality using email and password.
  • Cloud Data Synchronization: Real-time database integration (using Supabase or Firebase) to securely store and retrieve user habits.
  • Full CRUD Operations: The ability for users to Create, Read, Update, and Delete their daily tasks and habits.
7 Weeks Beginner
Lihat Detail Kursus

Artikel Terkait