Maîtriser les Opérations CRUD avec sqflite dans Flutter
Maîtriser les Opérations CRUD avec sqflite
dans Flutter
-
Que’st-ce que Database CRUD ?
- « CRUD » est un acronyme couramment utilisé dans le domaine de l’informatique, en particulier lorsqu’il s’agit de bases de données. Il signifie :
- C: Create (Créer)
- R: Read (Lire)
- U: Update (Mettre à jour)
- D: Delete (Supprimer)
- Dans le contexte de SQLite avec Flutter, le
CRUD
fait référence à l’ensemble des opérations de base qui peuvent être effectuées sur une base de données SQLite au sein d’une application Flutter. - Voici un bref aperçu de ces opérations :
Create
: Ajouter de nouvelles données à la base de données. En SQL, cela est généralement réalisé avec la commande INSERT.Read
: Récupérer des données existantes de la base de données. Cela est fait avec la commande SELECT en SQL.Update
: Modifier des données existantes dans la base de données. En SQL, cela est fait avec la commande UPDATE.Delete
: Supprimer des données de la base de données. Cela est réalisé avec la commande DELETE en SQL.- Flutter est un framework populaire pour le développement d’applications mobiles, et SQLite est une bibliothèque de gestion de bases de données relationnelles légère.
- Lorsqu’ils sont utilisés ensemble, ils permettent aux développeurs de créer des applications mobiles avec une gestion de données persistante et locale.
- La bibliothèque sqflite est la plus populaire pour intégrer SQLite dans Flutter, facilitant ainsi la mise en œuvre d’opérations CRUD.
-
Lecture (SELECT) :
- Pour lire des données depuis la base de données, vous pouvez utiliser :.
-
Méthode 1 : readDataWithCustomQuery(String sql) async
- Dans cette méthode, vous lui fournissez une requête SQL en tant que paramètre (sql), puis elle exécute cette requête à l’aide de la méthode rawQuery() de l’objet Database.
- La méthode rawQuery() est utilisée pour exécuter des requêtes SQL brutes. Cela signifie que vous pouvez exécuter n’importe quelle requête SQL valide à l’intérieur de sql.
- La méthode renvoie ensuite une liste de lignes sous forme de List<Map>, où chaque élément de la liste est un enregistrement représenté sous forme de map.
-
Méthode 2 : readDataFromTable() async
- Dans cette méthode, vous n’avez pas à fournir de requête SQL explicite. Au lieu de cela, vous ouvrez directement la base de données à l’aide de openDatabase() (vous devez avoir défini la table que vous souhaitez interroger au préalable).
- Ensuite, vous utilisez la méthode query() de l’objet db pour exécuter une requête SELECT sur la table spécifiée (my_table).
- Cette méthode renvoie également une liste de lignes sous forme de List<Map>, représentant les enregistrements dans la table.
-
Différences clés :
- La première méthode vous permet de fournir une requête SQL personnalisée, ce qui signifie que vous avez un contrôle plus précis sur ce que vous interrogez dans la base de données.
- La deuxième méthode est plus simple car elle ne nécessite pas de fournir de requête SQL. Cependant, elle est limitée à une opération SELECT sur la table préalablement définie.
- Dans l’ensemble, le choix entre ces deux méthodes dépendra de vos besoins spécifiques. Si vous avez besoin de flexibilité pour exécuter des requêtes SQL complexes et personnalisées, la première méthode peut être plus appropriée. Si vous voulez une approche plus simple et préférable lorsque vous interrogez régulièrement une table spécifique, la deuxième méthode pourrait être plus adaptée.
-
Insertion (INSERT) :
- Pour insérer des données dans la base de données, utilisez la méthode insert.
-
Méthode 1 : Future<int> insertData(String name, int age) async
- Dans cette méthode, vous spécifiez les données à insérer en tant que paramètres (name et age). Vous utilisez ensuite la méthode insert() de l’objet db pour insérer ces données dans la table spécifiée (my_table).
- Cette méthode renvoie un entier représentant l’ID de la ligne nouvellement insérée, ou -1 en cas d’erreur.
-
Méthode 2 : insertData(String sql) async
- Dans cette méthode, vous fournissez une requête SQL d’insertion en tant que paramètre (sql). Vous exécutez ensuite cette requête SQL à l’aide de la méthode rawInsert() de l’objet Database.
- Cette méthode renvoie également un entier, mais il est important de noter que son comportement dépend de la requête SQL fournie. Si la requête SQL est une instruction d’insertion valide, elle renverra l’ID de la ligne nouvellement insérée.
- Cependant, si la requête SQL est incorrecte ou mal formée, elle peut renvoyer -1 ou un autre code d’erreur.
-
Différences clés :
- La première méthode (insertData(String name, int age)) est plus sûre car elle utilise des paramètres pour passer les données d’insertion, ce qui protège contre les attaques par injection SQL et garantit que les données sont correctement échappées.
- La deuxième méthode (insertData(String sql)) nécessite de fournir une requête SQL brute en tant que paramètre, ce qui signifie que vous avez un contrôle complet sur la requête, mais vous devez être très prudent pour éviter les erreurs d’injection SQL.
- En résumé, la première méthode est généralement recommandée car elle est plus sûre et plus simple à utiliser pour les opérations d’insertion de données courantes. La deuxième méthode peut être utile si vous avez besoin d’une flexibilité totale pour créer des requêtes SQL personnalisées, mais elle nécessite une gestion plus attentive des requêtes.
-
Mise à jour (UPDATE) :
- Pour mettre à jour des données existantes, utilisez la méthode update.
-
Méthode 1 : Future<int> insertData(String name, int age) async
- Dans cette méthode, vous spécifiez les données à mettre à jour en tant que paramètres (id, name, age). Vous utilisez ensuite la méthode update() de l’objet db pour mettre à jour les données dans la table spécifiée (my_table).
- La méthode update() prend en charge des arguments spécifiques pour définir la clause WHERE (where et whereArgs) pour indiquer quelles lignes de la table doivent être mises à jour. Elle renvoie le nombre de lignes mises à jour.
-
Méthode 2 : updateData(String sql) async
- Dans cette méthode, vous fournissez une requête SQL d’update en tant que paramètre (sql). Vous exécutez ensuite cette requête SQL à l’aide de la méthode rawUpdate() de l’objet Database.
- Cette méthode renvoie également un entier, mais il est important de noter que son comportement dépend de la requête SQL fournie. Si la requête SQL est une instruction d’update valide, elle renverra le nombre de lignes mises à jour.
- Si la requête SQL est incorrecte ou mal formée, elle peut renvoyer -1 ou un autre code d’erreur.
-
Différences clés :
- La première méthode (updateData(int id, String name, int age)) est plus sûre car elle utilise des paramètres pour passer les données de mise à jour, ce qui protège contre les attaques par injection SQL et garantit que les données sont correctement échappées.
- La deuxième méthode (updateData(String sql)) nécessite de fournir une requête SQL brute en tant que paramètre, ce qui signifie que vous avez un contrôle complet sur la requête, mais vous devez être très prudent pour éviter les erreurs d’injection SQL.
- En résumé, la première méthode est généralement recommandée car elle est plus sûre et plus simple à utiliser pour les opérations de mise à jour de données courantes. La deuxième méthode peut être utile si vous avez besoin d’une flexibilité totale pour créer des requêtes SQL personnalisées, mais elle nécessite une gestion plus attentive des requêtes.
-
Suppression (DELETE) :
- Pour supprimer des données, utilisez la méthode delete.
- En utilisant ces méthodes, vous pouvez gérer les opérations courantes sur une base de données SQLite dans votre application Flutter. Assurez-vous de gérer les erreurs correctement en utilisant des blocs try-catch pour garantir la stabilité de votre application.
-
Applications
-
Tâche 1 : Création de la base de données SQLite
- Objectif
- Créer une base de données SQLite nommée « animaux » avec une table « type_animaux » dans une application Flutter à l’aide de Visual Studio Code.
- Étapes :
- Créez un nouveau projet Flutter dans Visual Studio Code.‘tp_nimaux‘
- Ouvrez le fichier main.dart dans le répertoire lib de votre projet.
- Supprimez tout le contenu par défaut du fichier main.dart.
- Ajoutez le package sqflite à votre fichier pubspec.yaml pour utiliser SQLite.
- En besoin utilisez les commandes suivantes
flutter pub upgrade --major-versions
etflutter pub outdated
- Créez un fichier Dart séparé pour gérer la base de données. Vous pouvez nommer ce fichier « sqlDataBase.dart« .
- Importez les packages nécessaires dans votre fichier Dart.
- Créez une fonction pour initialiser la base de données SQLite avec la table « type_animaux ».
- Créez un nouveau fichier Dart nommé « home.dart » dans le répertoire de votre projet Flutter.
- Dans « home.dart« , vous pouvez définir une classe HomeScreen pour cette partie de l’application.
- La page que vous devez réaliser doive ressemble à l’image suivant:
- Intégrez « HomeScreen » dans « main.dart«
- Dans « main.dart« , importez « home.dart » et utilisez la classe HomeScreen comme partie de votre application.
-
Tâche 2 : Insertion de données dans la base de données
- Objectif : Insérer des données (nom et espèce/type d’animaux) dans la table « type_animaux » de la base de données SQLite créée précédemment.
- Étapes :
- Créez une classe TypeAnimal pour représenter les données.
- Utilisez la première méthode d’insertion pour insérer des données dans la table « type_animaux ».
- Utilisez la deuxième méthode d’insertion (SQL brut) pour insérer des données dans la table « type_animaux ».
- Dans votre application, créez un formulaire avec des champs de texte pour saisir le nom et l’espèce/type de l’animal à insérer.
- Lorsque l’utilisateur soumet le formulaire, utilisez l’une des méthodes d’insertion pour ajouter le type d’animal à la table « type_animaux ».
- Affichez un message de confirmation pour indiquer que l’insertion a réussi.
-
Tâche 3 : Affichage des enregistrements dans un ListView
- Objectif
- Afficher les enregistrements de la table « type_animaux » dans un ListView en utilisant deux méthodes différentes.
- Étapes :
- Créez une liste pour stocker les enregistrements récupérés de la base de données.
- Utilisez la méthode getTypeAnimaux pour obtenir les enregistrements de la table « type_animaux » et les stocker dans la liste typeAnimauxList.
- Créez un widget ListView.builder pour afficher la liste des enregistrements dans votre interface utilisateur.
- Vous pouvez maintenant afficher la liste des enregistrements dans votre application sous le formulaire d’insertion.
-
Tâche 4 : Ajouter les méthodes de modification et de suppression.
- Votre application doit ressemble à l’image suivant:
-
Fichiers sources
- Fichier main.dart
- Fichier home.dart
- Fichier liste_animaux.dart
- Fichier sqlDataBase.dart
- Fichier updateAnimaux.dart
Future<List<Map<String, dynamic>>> readDataWithCustomQuery(String sql) async {
Database? mydb = await db;
List<Map> response = await mydb!.rawQuery(sql);
return response;
}
Future<List<Map<String, dynamic>>> readData() async {
final db = await openDatabase();
return await db.query('my_table');
}
Future<int> insertData(String name, int age) async {
final db = await openDatabase();
return await db.insert('my_table', {'name': name, 'age': age});
}
Future<int> insertData(String sql) async {
Database? mydb = await db ;
int response = await mydb!.rawInsert(sql);
return response ;
}
Future<int> updateData(int id, String name, int age) async {
final db = await openDatabase();
return await db.update(
'my_table',
{'name': name, 'age': age},
where: 'id = ?',
whereArgs: [id],
);
}
updateData(String sql) async {
Database? mydb = await db ;
int response = await mydb!.rawUpdate(sql);
return response ;
}
Future<int> deleteData(int id) async {
final db = await openDatabase();
return await db.delete(
'my_table',
where: 'id = ?',
whereArgs: [id],
);
}
dependencies:
path_provider: ^2.1.0
path: ^1.6.4
sqflite: ^2.3.0
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
// sqlDataBase.dart
Future<Database> openDataBase() async {
final databasePath = await getDatabasesPath();
final path = join(databasePath, 'animaux.db');
return openDatabase(path, version: 1, onCreate: (db, version) async {
// Créez ici la structure de votre table "type_animaux".
await db.execute('''
CREATE TABLE type_animaux (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nom TEXT NOT NULL,
espece TEXT NOT NULL
)
''');
});
}
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State {....................
Solution
import 'package:flutter/material.dart';
import 'sqlDataBase.dart';
import 'liste_animaux.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Mon App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
TextEditingController nomController = TextEditingController();
TextEditingController especeController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Ajouter un Animal'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
TextField(
controller: nomController,
decoration: const InputDecoration(labelText: 'Nom de l\'animal'),
),
TextField(
controller: especeController,
decoration: const InputDecoration(labelText: 'Espèce de l\'animal'),
),
const SizedBox(height: 20.0),
ElevatedButton(
onPressed: () async {
final nom = nomController.text;
final espece = especeController.text;
if (nom.isNotEmpty && espece.isNotEmpty) {
final db = SqlDb();
final id = await db.insertTypeAnimal(nom, espece);
if (id != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Animal ajouté avec succès (ID: $id)'),
),
);
nomController.clear();
especeController.clear();
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Erreur lors de l\'ajout de l\'animal.'),
),
);
}
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Veuillez remplir tous les champs.'),
),
);
}
},
child: const Text('Ajouter un Animal'),
),
const SizedBox(height: 20.0),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const ListeAnimauxScreen()),
);
},
child: const Text('Voir la liste des animaux'),
)
],
),
),
);
}
}
import 'package:flutter/material.dart';
import 'home.dart'; // Importez le fichier home.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Mon Application',
home: HomeScreen(), // Utilisez HomeScreen comme page d'accueil
);
}
}
class TypeAnimal {
final String nom;
final String espece;
TypeAnimal(this.nom, this.espece);
}
Future<int> insertTypeAnimal(String nom, String espece) async {
final db = await openDatabase();
return await db.insert('type_animaux', {'nom': nom, 'espece': espece});
}
Future<int> insertTypeAnimal(String sql) async {
Database? mydb = await db;
int response = await mydb!.rawInsert(sql);
return response;
}
List typeAnimauxList = [];
Ajoutez une fonction pour récupérer les enregistrements de la table « type_animaux » depuis la base de données.
Future<List<TypeAnimal>> getTypeAnimaux() async {
final db = await openDatabase();
final List<Map<String, dynamic>> maps = await db.query('type_animaux');
return List.generate(maps.length, (i) {
return TypeAnimal(
maps[i]['nom'],
maps[i]['espece'],
);
});
}
typeAnimauxList = await getTypeAnimaux();
ListView.builder(
itemCount: typeAnimauxList.length,
itemBuilder: (context, index) {
final typeAnimal = typeAnimauxList[index];
return ListTile(
title: Text(typeAnimal.nom),
subtitle: Text(typeAnimal.espece),
);
},
)