Les bases de données sont des éléments incontournables dans le domaine des applications informatiques. Elles constituent la mémoire longue des applications qui les utilisent. C’est à dire, pour enregistrer les informations de ses utilisateurs afin que ceux-ci puissent être reconnus à chaque fois qu’ils se connectent par exemple, une application (web, mobile ou autre) a besoin d’une base de données pour sauvegarder ces informations.
Dans cet article, nous verrons comment utiliser une base de données relationnelle dans une application Flutter. Cet article fait suite à l’article Développez votre première application mobile en Flutter.
Installation du plugin sqflite
Pour utiliser une base de données en Flutter, nous allons utiliser le plugin sqflite qui fournira tous les outils nécessaires pour créer et gérer efficacement notre base de données locale. Vous pouvez voir l’article Utilisez les plugins en Flutter pour apprendre comment installer un plugin dans un projet flutter et aussi comment l’utiliser.
dependencies:
flutter:
sdk: flutter
path: ^1.8.1
sqflite: ^2.0.3+1
Configuration du plugin
Pour commencer, nous allons créer un repertoire database dans le repertoire models de notre projet. Puis un fichier dao.dart dans le repertoire database qui vient d’être créé. Ce fichier contiendra la classe Dao qui nous permettra d’effectuer des actions dans notre base de données.
NB: cet article est une continuité de l’article Développez votre première application mobile en Flutter dans lequel nous avons construit les écrans d’une application de gestion de bibliothèque.
Création de la base de données
Nous avons besoin, pour utiliser notre base de données, d’ouvrir la base si elle existe dans le cas contraire, nous devons la créer puis l’ouvrir. Notre base de données s’appellera bibliotheca.db Nous allons alors écrire des méthodes dans notre classe Dao
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
class Dao {
//La reférence de notre base de données
static Database? _database;
//Un getter qui renvoie l'objet de base de donnée.
//Si la base n'existe pas _initDB la créé
static Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDB('bibliotheca.db');
return _database!;
}
//_initDB initialise notre base de données.
static Future<Database> _initDB(String filePath) async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, filePath);
//openDatabase ouvre notre base de données située à l'emplacement "path"
//si la base n'existe pas openDatabase exécute _createDB
return await openDatabase(path, version: 1, onCreate: _createDB);
}
//_createDB est la méthode qui s'occupe de la définition des tables de notre base de données
//_createDB exécute les transactions de base de données pour créer les tables
static Future _createDB(Database db, int version) async {...}
}
- _database est la reférence de notre base de données
- database est un getter qui renvoie l’objet de base de données. Si la base n’existe pas, _initDB la créé.
- _initDB initialise notre base de données.
- _createDB est la méthode qui s’occupe de la définition des tables de notre base de données. Elle exécute les transactions de base de données pour créer les tables.
Création des tables
Pour créer les tables de notre base de données bibliotheca.db, nous allons utiliser le modèle ci-dessous :
En se basant sur ces schémas, nous pouvons écrire le scripts SQL pour créer la table :
Catégorie
CREATE TABLE categorie (
id INTEGER PRIMARY KEY AUTOINCREMENT,
libelle VARCHAR(255) NOT NULL
)
Auteur
CREATE TABLE auteur (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nom VARCHAR(255) NOT NULL,
prenoms VARCHAR(255) NOT NULL,
email VARCHAR(255)
)
Livre
CREATE TABLE livre (
id INTEGER PRIMARY KEY AUTOINCREMENT,
libelle VARCHAR(255) NOT NULL,
description TEXT,
auteur_id INTEGER NOT NULL,
categorie_id INTEGER NOT NULL
)
Nous allons utiliser la méthode _create pour créer nos tables.
...
static Future _createDB(Database db, int version) async {
await db.execute('''
CREATE TABLE auteur (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nom VARCHAR(255) NOT NULL,
prenoms VARCHAR(255) NOT NULL,
email VARCHAR(500)
)
''');
await db.execute('''
CREATE TABLE categorie (
id INTEGER PRIMARY KEY AUTOINCREMENT,
libelle VARCHAR(255) NOT NULL
)
''');
await db.execute('''
CREATE TABLE livre (
id INTEGER PRIMARY KEY AUTOINCREMENT,
libelle VARCHAR(255) NOT NULL,
image VARCHAR(100) NOT NULL,
description VARCHAR(500),
auteur_id INTEGER NOT NULL,
categorie_id INTEGER NOT NULL
)
''');
}
...
Maintenant que nous avons créé notre base de données, nous allons manipuler les données de la base pour lire, y ajouter, modifier et supprimer des données.
Manipulation de la base de données
Nous allons, pour illustrer, effectuer des manipulations dans la table categorie.
Avant de commencer, nous avons besoin d’ajouter dans notre classe Categorie un constructeur fromJson et une méthode toJson pour faciliter nos transaction avec la base de données.
class Categorie {
int? id;
String? libelle;
Categorie({this.id, this.libelle});
Categorie.fromJson(Map<String, dynamic> json) {
id = json["id"];
libelle = json["libelle"];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> map = {};
map["id"] = id;
map["libelle"] = libelle;
return map;
}
}
- Categorie.fromJson(Map json) est un constructeur qui créé un objet catégorie à partir d’une Map.
- Map toJson() est une méthode qui permet de convertir un objet catégorie en Map.
Lecture des données
static Future<List<Categorie>> listeCategorie() async {
final db = await database;
final maps = await db.query(
"categorie",
columns: ["*"],
);
if (maps.isNotEmpty) {
return maps.map((e) => Categorie.fromJson(e)).toList();
} else {
return [];
}
}
Insertion de données
static Future<Categorie> createCategorie(Categorie categorie) async {
final db = await database;
final id = await db.insert("categorie", categorie.toJson());
categorie.id = id;
return categorie;
}
Mise à jour de données
static Future<int> updateCategorie(Categorie categorie) async {
final db = await database;
return db.update(
"categorie",
categorie.toJson().remove("id"), //Nous prenons soin de supprimer le champs id avec ..remove("id")
where: 'id = ?',
whereArgs: [categorie.id],
);
}
NB: Nous prenons soin de supprimer le champs id avec ..remove(« id ») de la map renvoyée par la méthode toJson.
Suppression de données
static Future<int> delete(int id) async {
final db = await database;
return await db.delete(
"categorie",
where: 'id = ?',
whereArgs: [id],
);
}
Grâce à ces différentes méthodes, nous pouvons effectuer des insertions, mises à jour, suppressions et lectures dans la table catégorie.
Code complet
import 'package:bibliotheca/models/categorie.dart';
import 'package:bibliotheca/views/liste_categorie.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
class Dao {
//La reférence de notre base de données
static Database? _database;
//Un getter qui renvoie l'objet de base de donnée.
//Si la base n'existe pas _initDB la créé
static Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDB('bibliotheca.db');
return _database!;
}
//_initDB initialise notre base de données.
static Future<Database> _initDB(String filePath) async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, filePath);
//openDatabase ouvre notre base de données située à l'emplacement "path"
//si la base n'existe pas openDatabase exécute _createDB
return await openDatabase(path, version: 1, onCreate: _createDB);
}
//_createDB est la méthode qui s'occupe de la définition des tables de notre base de données
//_createDB exécute les transactions de base de données qui pour créer les tables
static Future _createDB(Database db, int version) async {
await db.execute('''
CREATE TABLE auteur (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nom VARCHAR(255) NOT NULL,
prenoms VARCHAR(255) NOT NULL,
email VARCHAR(255)
)
''');
await db.execute('''
CREATE TABLE categorie (
id INTEGER PRIMARY KEY AUTOINCREMENT,
libelle VARCHAR(255) NOT NULL
)
''');
await db.execute('''
CREATE TABLE livre (
id INTEGER PRIMARY KEY AUTOINCREMENT,
libelle VARCHAR(255) NOT NULL,
description TEXT,
auteur_id INTEGER NOT NULL,
categorie_id INTEGER NOT NULL
)
''');
}
static Future<List<Categorie>> listeCategorie() async {
final db = await database;
final maps = await db.query(
"categorie",
columns: ["*"],
);
if (maps.isNotEmpty) {
return maps.map((e) => Categorie.fromJson(e)).toList();
} else {
return [];
}
}
static Future<int> updateCategorie(Categorie categorie) async {
final db = await database;
return db.update(
"categorie",
categorie.toJson().remove("id"),
where: 'id = ?',
whereArgs: [categorie.id],
);
}
static Future<Categorie> createCategorie(Categorie categorie) async {
final db = await database;
final id = await db.insert("categorie", categorie.toJson());
categorie.id = id;
return categorie;
}
static Future<int> delete(int id) async {
final db = await database;
return await db.delete(
"categorie",
where: 'id = ?',
whereArgs: [id],
);
}
}
Test de la base de données
import 'package:bibliotheca/models/categorie.dart';
import 'package:bibliotheca/models/database/dao.dart';
import 'package:bibliotheca/views/home_page.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
//Insertion
var cat = Categorie(libelle: "dramatuge");
cat = await Dao.createCategorie(cat);
await affichage();
//Mise à jour
cat.libelle = "Poème";
await Dao.updateCategorie(cat);
await affichage();
//Suppression
await Dao.delete(cat.id!);
await affichage();
// runApp(
// MaterialApp(
// title: "Bibliotheca",
// theme: ThemeData(primaryColor: Colors.blue),
// home: const HomePage(),
// ),
// );
}
Future affichage() async {
//Lecture des données
var cats = await Dao.listeCategorie();
print(cats.map((e) => e.toJson()).toList());
}
Conclusion
Dans cet article nous avons appris à installer, configurer et utiliser une base de données dans une application Flutter. Vous pouvez, bien-sur, adapter les différents codes fourni dans cet article à vos besoins. J’espère que cet article vous sera d’une grande utilité. Je vous partage le code complet de ce projet. Byyyyyye 😁.
It’s a pity you don’t have a donate button! I’d certainly donate to this
excellent blog! I suppose for now i’ll settle for book-marking and adding your RSS feed
to my Google account. I look forward to brand new updates and will share this site with my Facebook group.
Chat soon!
super bonne continuation