Complete SQLite CRUD Operations in Flutter - CodAffection

Complete SQLite CRUD Operations in Flutter

Flutter CRUD Operations with SQLite DB

Introduction

Now a days almost all application have to have some kind of data storage. Application without collaboration with other users will make use of local storage db – SQLite. In this tutorial, we are going to cover all CRUD operations in Flutter with SQLite.

The design part of the project already covered in previous tutorial – Design Flutter Form and ListView Widget for CRUD Operation. It includes form design and list of records inserted from the form, where we saved list of records in widget state object. So in this tutorial we can focus on SQLite CRUD Operations and finally we update existing events with SQLite CRUD Operation. Application from previous tutorial looks like this.

Flutter Form Design with TextField and Submit button
Showing Flutter ListView widget, populated with data

Let’s get Started

First of all, let’s add dependencies for this project, for that update pubspec.yaml file as follows.


dependencies:
  flutter:
    sdk: flutter
  sqflite: any
  path_provider: any

Additionally here we’ve two packages sqflite and path_provider . sqflite helps to work with SQLite database. To find commonly used locations on file system, we use  path_provider package.

Caution: When it comes to yaml files, indentation is very important. Before the package name we need 2 spaces and before version name there should be a space. Instead of exact version we use 'any' , so latest version will be used.

Now let’s update contact model – models/contact.dart .

First of all, you could see few string constance with table name and column names. In this application, we are dealing with contact information including full name and mobile number. Other than from a normal constructor, we have a named constructor fromMap for initializing an instance from a given map object. And with toMap function, we will convert contact object to the corresponding map object.

why map object?

In SQLite database, records are stored as a collection of map objects. In case if you don’t know – basically map is a <key, value> pair. for example –

So before inserting a record into SQLite database file, we’ve to convert the record into corresponding map object. While retrieving records from the db, it returns collection of map objects.

Getting Started with Database

To handle database related operations, we’ve created a new file – util/database_helper.dart.

Here we’ve a class DatabaseHelper with a private named constructor _() . here the name of this constructor is _ , yes it is possible. There is a final static property instance of the type – DatabaseHelper , which is initialized with _() constructor. Because of this final property, it can’t change it’s value after initialization. Hence this is a singleton class (Meaning only one instance of the class is created in through out the app). There is public getter- database , which returns the Database instance. If _database is not initialized _initDatabase function will be called.

Inside _initDatabse() , dataDirectory is initialized with getApplicationDocumentsDirectory function, which is from path_provider package. Basically this function returns the location where database is stored. which is different for android and ios operating system. But it’s handled by the path_provider package. The path is joined with database name as our database file path. To connect and return the database reference openDatabase function is called. version property is just to indicate database version not actual SQLite version. The version is compared within source code with the version in actual physical db. If there is a difference. we can go for upgrade or downgrade process. we are not going to discuss that in this tutorial.

If there is no database with the given db path, we’ve to create the database schema with all the tables. That’s what we’ve done with onCreate property function _onCreateDB() . Inside the function we create contact table.

SQLite CRUD Operations

Now let’s add these function to DatabaseHelper class for CRUD Operations – insert, update, delete and retrieve.

With sqflite package, there are two kind of function one with raw query and a direct function with all required parameters without query. For example, for insert operation we called direct function insert() . instead of that you can also call rawInsert() with raw insert query like ‘insert into contact values …’. Before inserting the record we have to convert the contact object to corresponding map object.

For update and delete operation, where and whereArgs parameters are used to pass additional filter operation. To retrieve all the records from contact table, we called the function query() . The function returns, a list of map objects. Finally we converted the List<Map> into List<Contact> .

Wire up All events

So far we only touched Contact model and DatabaseHelper class files. Now let’s consume these function inside widget events. As I mentioned before, the UI of this app is discussed in previous article here. First of let’s look how to retrieve all contact records from the contact table.

We’ve imported the DatabaseHelper class at the top. Inside MyHomePage widget, we’ve overridden initState method, it will be called once when widget state objects are created. The function can be used to perform initialization of dependent properties/ objects. After calling parent method – super.initState() , _dbHelper instance is initialized with final instance property. After that, to retrieve all of the records from contact table we’ve called the function _refreshContactList() . Inside the function we’ve called the function, fetchContacts() is called to return list of contact records and it is assigned to _contacts state object.

Caution: If you already running your app, stop and re-run the app. because the initState() method won’t be called with Hot-Reload.

Now let’s update form submit event function _onSubmit() . Previously we’ve been adding the contact information to _contacts list directly. Instead of that, we called the insertContact() method to insert the record into SQLite DB.

Edit and Delete Operation

First of all, let’s implement edit/update operation. When user tap on ListTile widget, corresponding contact information should populated to respective text-field. Then user can make required changes and followed by form submission. The event can be implemented with _showForEdit() function as below.


class _MyHomePageState extends State {
  
  final _ctrlName = TextEditingController();
  final _ctrlMobile = TextEditingController();
  ...

  ListTile(
    ...,
    onTap: () {
    _showForEdit(index);
    },
  )
  
  _form => Container(
    TextFormField(
    controller: _ctrlName,
    ...
    ),
    TextFormField(
    controller: _ctrlName,
    ...
    ),
    ...
  )

  _showForEdit(index) {
    setState(() {
      _contact = _contacts[index];
      _ctrlName.text = _contacts[index].name;
      _ctrlMobile.text = _contacts[index].mobile;
    });
  }
}

Initially, you could see two TextEditionController , _ctrlName and _ctrlMobile . These properties are assigned to respective text-field controller property. Then only we can change the field value inside the tap event. _showForEdit() function is wired up to the ListTile – onTap event. Inside the function, we change _contact object and text-field values with selected record details.

Now let’s do the update operation inside the form submit event. where we’ve already implemented the insert operation. since we’ve update _contact object inside _showForEdit() function. here we can check the id of record. based on that we decide whether we’ve an insert or update operation.


_onSubmit() async {
 ...
 if (_contact.id == null)
  await _dbHelper.insertContact(_contact);
 else
  await _dbHelper.updateContact(_contact);
 _resetForm();
 ...
}

Since we change text-field value through TextEditingController , we have to clear the controller separately after form reset operation. so new function _resetForm() is defined for reset operation. along with usual procedure for a form reset operation, we have set the id to null. so the form is cleared for an insert operation.


_resetForm() {
  setState(() {
    _formKey.currentState.reset();
    _ctrlName.clear();
    _ctrlMobile.clear();
    _contact.id = null;
  });
}

Delete Operation

For delete operation, we’ve to add a delete button inside ListTilewidget.


ListTile(
...
trailing: IconButton(
    icon: Icon(Icons.delete_sweep, color: darkBlueColor),
    onPressed: () async {
      await _dbHelper.deleteContact(_contacts[index].id);
      _resetForm();
      _refreshContactList();
    }),
...
)

Inside the onPressed event, we’ve deleted the corresponding record.

That’s it guys. Hope you found this helpful.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top
1 Share
1 Share
Share via
Copy link