Sebelumnya kita telah membahas penyimpanan lokal dengan menggunakan shared_preferences. Kali ini kita bakal bahas tentang sqflite. SQFLite adalah penyimpanan data lokal yang mana bentuknya itu berupa table. Jika kita membutuhkan penyimpanan lokal berupa table, package ini merupakan opsi terbaik yang tersedia untuk saat ini.
Tulisan ini termasuk ke pada rangkaian pembahasan penyimpanan data lokal pada Flutter:
- Penyimpanan data lokal pada Flutter (shared_preferences)
- [Tulisan ini] Penyimpanan data lokal pada Flutter (SQFLite)
- Cara untuk melakukan migration pada sqflite
Kita langsung aja ke code ya, Yuk Ngoding,
1. Tambahkan package
Pada pubspec.yaml tambahkan package dan jalankan flutter pub get
sqflite: ^2.2.8+4
2. MySqflite.dart
Pada tulisan ini kita akan menyimpan data Siswa. Disini kita akan menambahkan beberapa file. File pertama yang akan kita buat adalah file Constant.
class Constant {
static const studentId = 'id';
static const studentName = 'name';
static const studentDepartment = 'department';
static const studentSKS = 'sks';
}
- Constant ini nantinya akan kita gunakan untuk proses convert model siswa menjadi string (atau sebaliknya) dan juga untuk proses SQFLite
- Ini hanyalah salah satu opsi agar menghindari typo ketika penulisan code.
Setelah itu kita lanjut untuk membuat class Siswa (Student)
import '../commons/const.dart';
class StudentModel {
String id;
String name;
String department;
int sks;
StudentModel({
required this.id,
required this.name,
required this.department,
required this.sks,
});
// Convert into a Map. The keys must correspond to the names of the
// columns in the database.
Map<String, dynamic> toMap() {
return {
Constant.studentId: id,
Constant.studentName: name,
Constant.studentDepartment: department,
Constant.studentSKS: sks,
};
}
}
- Pada class model ini kita menambahkan function toMap() untuk memudahkan penggunaan di class SQFLite
- Sesuaikan code import dengan struktur folder temen-temen
Setelah itu kita lanjut ke MySQFLite.dart.
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import '../../commons/const.dart';
import '../../models/student_model.dart';
class MySQFLite {
static const _databaseName = "MyDatabase.db";
static const _databaseV1 = 1;
static const tableStudent = 'Student';
// Singleton class
MySQFLite._privateConstructor();
static final MySQFLite instance = MySQFLite._privateConstructor();
static Database? _database;
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
_initDatabase() async {
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, _databaseName);
return await openDatabase(path, version: _databaseV1,
onCreate: (db, version) async {
var batch = db.batch();
_onCreateTableStudent(batch);
await batch.commit();
});
}
void _onCreateTableStudent(Batch batch) async {
batch.execute('''
CREATE TABLE $tableStudent (
${Constant.studentId} TEXT PRIMARY KEY,
${Constant.studentName} TEXT,
${Constant.studentDepartment} TEXT,
${Constant.studentSKS} INTEGER
)
''');
}
// Other Function
}
- Class merupakan singleton agar bisa diakses melalui instance
- Kita membuat beberapa static variable, agar ketika pengoperasian sqflite kita bisa mengacu ke variable tersebut dan terhindar dari typo.
- Pada method _initDatabase kita mendifinikasan path dari sqflite, beserta nama, versi, dan juga proses onCreate. Ketika mengalami kenaikan versi kita menambahkan onUpgrade pada method ini. (Terkait migrasi database kita bahas di tulisan selanjutnya ya.)
- Sesuaikan code import dengan struktur folder temen-temen
Lanjut ke function-function lainnya. Code-code berikut ini bisa temen-temen tambahkan di class MySQFLite sesuai dengan kebutuhan ya.
a. Insert
Future<int> insertStudent(StudentModel model) async {
Database db = await instance.database;
return await db.insert(
tableStudent,
model.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
Future<void> insertStudents(List<StudentModel> models) async {
Database db = await instance.database;
Batch batch = db.batch();
for (var model in models) {
batch.insert(tableStudent, model.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace);
}
await batch.commit(noResult: true);
}
- Function ini digunakan untuk menambahkan data ke SQFLite
- Kita menggunakan ConflictAlgorithm.replace, sehingga jika nantia ada data yang sama, data tersebut akan ditimpa dengan data yang baru
- Disini kita menggunaka toMap() yang telah kita sediakan sebelumnya di class Student
- Kita menggunakan batch untuk melakukan insert data yang banyak sekaligus
b. Get
Future<List<StudentModel>> getStudents() async {
Database db = await instance.database;
// var allData = await db.rawQuery("SELECT * FROM $tableStudent");
var allData = await db.query(tableStudent);
return List.generate(allData.length, (i) {
return StudentModel(
id: allData[i][Constant.studentId] as String,
name: allData[i][Constant.studentName] as String,
department: allData[i][Constant.studentDepartment] as String,
sks: int.parse(
allData[i][Constant.studentSKS].toString(),
),
);
});
}
Future<StudentModel?> getStudentById(String id) async {
Database db = await instance.database;
// var allData = await db
// .rawQuery("SELECT * FROM $tableStudent WHERE ${Constant.studentId} = "
// "$id LIMIT 1");
var allData = await db.query(
tableStudent,
where: '${Constant.studentId} = ?',
whereArgs: [id],
);
if (allData.isNotEmpty) {
return StudentModel(
id: allData[0][Constant.studentId] as String,
name: allData[0][Constant.studentName] as String,
department: allData[0][Constant.studentDepartment] as String,
sks: int.parse(allData[0][Constant.studentSKS] as String));
}
return null;
}
- Untuk melakukan pengambilan data, kita bisa menggunakan query atau bisa juga dengan rawQuery
c. Update & Delete
Future<int> updateStudentDepartment(StudentModel model) async {
Database db = await instance.database;
// return await db.rawUpdate(
// 'UPDATE $tableStudent SET ${Constant.studentName} = ${model.name}, '
// '${Constant.studentDepartment} = ${model.department}, '
// '${Constant.studentSKS} = ${model.sks} '
// 'Where ${Constant.studentId} = ${model.id}',
// );
return await db.update(
tableStudent,
model.toMap(),
where: '${Constant.studentId} = ?',
whereArgs: [model.id],
);
}
Future<int> deleteStudent(String id) async {
Database db = await instance.database;
// return await db.rawDelete(
// 'DELETE FROM $tableStudent Where ${Constant.studentId} = $id',
// );
return await db.delete(
tableStudent,
where: '${Constant.studentId} = ?',
whereArgs: [id],
);
}
clearAllData() async {
Database db = await instance.database;
// await db.rawQuery("DELETE FROM $tableStudent");
await db.delete(tableStudent);
}
- Kurang lebih sama dengan Get kita bisa menggunakan query manual atau dengan Helper yang udah disediakan oleh SQFLite
3. Screen
Pada bagian screen kita hanya akan mencoba untuk menyimpan data ke SQFLite, dan menampilkannya. Gunakan code berikut ini:
import 'package:explore_storage/repository/local/sqflite.dart';
import 'package:flutter/material.dart';
import '../models/student_model.dart';
class StudentsScreen extends StatefulWidget {
const StudentsScreen({super.key});
@override
State<StudentsScreen> createState() => _StudentsScreenState();
}
class _StudentsScreenState extends State<StudentsScreen> {
final keyFormStudent = GlobalKey<FormState>();
TextEditingController controllerId = TextEditingController();
TextEditingController controllerName = TextEditingController();
TextEditingController controllerDepartment = TextEditingController();
TextEditingController controllerSks = TextEditingController();
String id = "";
String name = "";
String department = "";
int sks = 0;
List<StudentModel> students = [];
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
students = await MySQFLite.instance.getStudents();
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Explore SQFLite"),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
margin: const EdgeInsets.only(top: 36, left: 24, bottom: 4),
child: const Text(
"Input Student",
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
Form(
key: keyFormStudent,
child: Container(
margin: const EdgeInsets.only(left: 24, right: 24),
child: Column(
children: [
TextFormField(
controller: controllerId,
decoration: const InputDecoration(hintText: "ID"),
validator: (value) => _onValidateText(value),
keyboardType: TextInputType.number,
onSaved: (value) => id = value.toString(),
),
TextFormField(
controller: controllerName,
decoration: const InputDecoration(hintText: "Name"),
validator: (value) => _onValidateText(value),
onSaved: (value) => name = value.toString(),
),
TextFormField(
controller: controllerDepartment,
decoration: const InputDecoration(hintText: "Department"),
validator: (value) => _onValidateText(value),
onSaved: (value) => department = value.toString(),
),
TextFormField(
controller: controllerSks,
decoration: const InputDecoration(hintText: "SKS"),
validator: (value) => _onValidateText(value),
keyboardType: TextInputType.number,
onSaved: (value) => sks = int.parse(value.toString()),
),
],
),
),
),
Container(
margin: const EdgeInsets.only(left: 24, right: 24),
child: ElevatedButton(
onPressed: _onSaveStudent,
child: const Text("Save"),
),
),
Container(
margin: const EdgeInsets.only(top: 24, left: 24, bottom: 4),
child: const Text("Student Data",
style: TextStyle(fontWeight: FontWeight.bold)),
),
Expanded(
child: ListView.builder(
itemCount: students.length,
padding: const EdgeInsets.fromLTRB(24, 0, 24, 8),
itemBuilder: (BuildContext context, int index) {
var value = students[index];
return Container(
margin: const EdgeInsets.only(bottom: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
Text("Id: ${value.id}"),
Text("Name: ${value.name}"),
Text("Department: ${value.department}"),
Text("SKS: ${value.sks}"),
],
),
);
},
),
)
],
),
);
}
String? _onValidateText(String? value) {
if (value?.isEmpty ?? true) return 'Can\'t empty';
return null;
}
_onSaveStudent() async {
FocusScope.of(context).requestFocus(FocusNode());
if (keyFormStudent.currentState?.validate() ?? false) {
keyFormStudent.currentState?.save();
controllerId.text = "";
controllerName.text = "";
controllerDepartment.text = "";
controllerSks.text = "";
await MySQFLite.instance.insertStudent(StudentModel(
id: id,
name: name,
department: department,
sks: sks,
));
students = await MySQFLite.instance.getStudents();
setState(() {});
}
}
}
4. Hasil
Setelah itu, panggil class StudentsScreen di runApp. Maka hasilnya kurang lebih akan seperti berikut:

Sekian tulisan kali ini, terimakasih dan semoga bermanfaat ya 😀
Tulisan ini termasuk ke pada rangkaian pembahasan penyimpanan data lokal pada Flutter:
- Penyimpanan data lokal pada Flutter (shared_preferences)
- [Tulisan ini] Penyimpanan data lokal pada Flutter (SQFLite)
- Cara untuk melakukan migration pada Sqflite
Oh iya di website ini ada tulisan menarik lainnya juga loh, seperti berikut:
apakah penggunaan penyimpanan lokal, dapat berjalan pada flutlab?
Saya sendiri belum pernah menggunakan flutlab. Tapi karena flutlab adalah IDE, ya harusnya pengunaan penyimpanan lokal bisa dilakukan.
mantap tutorialnya bang, sudah berhasil. tapi mungkin berikan juga tutorial delete data dan update nya bang, terimakasih
Ok selamat & terimakasih atas masukannya 😀