Se, per la nostra app, abbiamo bisogno di dati persistenti e di eseguire query su grandi quantità di dati sul dispositivo locale, sarebbe meglio utilizzare un database invece di un file locale o di un archivio di valori-chiave. In generale, i database forniscono inserimenti, aggiornamenti e query più rapidi rispetto ad altre soluzioni di persistenza locale.
Le app Flutter possono utilizzare i database SQLite tramite il plug-in sqflite
disponibile su pub.dev
. In questo esempio mostriamo le basi dell'utilizzo di sqflite
per inserire, leggere, aggiornare e rimuovere dati relativi a varie persone.
Questo esempio si compone dei seguenti passaggi:
Per utilizzare il database SQLite, importare i pacchetti sqflite
e path
.
Il pacchetto sqflite
fornisce classi e funzioni per interagire con un database SQLite.
Il pacchetto path
fornisce funzioni per definire la posizione in cui archiviare il database su disco.
dependencies:
flutter:
sdk: flutter
sqflite:
path:
Assicurati di importare i pacchetti nel file in cui lavorerai.
import 'dart:async';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
Prima di creare la tabella per memorizzare le informazioni sulle Persone, definiamo i dati che devono essere memorizzati. Per questo esempio, definiamo una classe Persona che contiene tre dati: un id
univoco, il nome
e l'età
di ogni persona.
class Persona {
final int id;
final String nome;
final int eta;
Persona({
required this.id,
required this.nome,
required this.eta,
});
}
Prima di leggere e scrivere dati nel database, dobbiamo aprire una connessione al database. Ciò comporta due passaggi:
Nota: per utilizzare la parola chiave await, il codice deve essere inserito all'interno di una funzione asincrona. Dobbiamo posizionare tutte le seguenti funzioni della tabella all'interno void main() async {}.
// Evita errori causati da upgrade di Flutter.
// È necessario importare 'package:flutter/widgets.dart'
WidgetsFlutterBinding.ensureInitialized();
// Apri il database e memorizza il riferimento.
final database = openDatabase(
// Imposta il percorso del database. Nota: utilizzare la funzione ‘join’ dal
// pacchetto ‘path’ è il modo migliore per assicurarsi che il percorso sia
// corretto per ogni piattaforma
join(await getDatabasesPath(), 'database_persone.db'),
);
Creiamo una tabella per memorizzare informazioni sulle varie persone. Per questo esempio, creiamo una tabella denominata persone che definisce i dati che possono essere archiviati. Ogni persona contiene un ID, un nome e un'età. Pertanto, questi sono rappresentati come tre colonne nella tabella delle persone.
final database = openDatabase(
// Imposta il percorso del database. Nota: utilizzare la funzione ‘join’ dal
// pacchetto ‘path’ è il modo migliore per assicurarsi che il percorso sia
// corretto per ogni piattaforma
join(await getDatabasesPath(), 'database_persone.db'),
// Quando il database viene creato per la prima volta, crea una tabella per memorizzare le persone.
onCreate: (db, version) {
// Esegui il comando CREATE TABLE sul database.
return db.execute(
'CREATE TABLE persone(id INTEGER PRIMARY KEY, nome TEXT, eta INTEGER)',
);
},
// Imposta la versione. Questo esegue la funzione onCreate e fornisce un percorso per eseguire upgrade e downgrade del database.
version: 1,
);
Ora che abbiamo un database con una tabella adatta a memorizzare informazioni sulle varie persone, è il momento di leggere e scrivere dati.
Per prima cosa, inseriamo una persona nella tabella delle persone. Ciò comporta due passaggi:
class Persona {
final int id;
final String nome;
final int eta;
Persona({
required this.id,
required this.nome,
required this.eta,
});
// Converti una Persona in una Map. Le chiavi devono essere uguali ai nomi delle
//colonne nel database.
Map<String, dynamic> toMap() {
return {
'id': id,
'nome': nome,
'eta': eta,
};
}
// Implementa toString per rendere piu semplice visualizzare informazioni su
// ogni persona quando viene utilizzato il comando print.
@override
String toString() {
return 'Persona{id: $id, nome: $nome, eta: $eta}';
}
}
// Definisci una funzione che inserisce le persone nel database
Future<void> insertPersona(Persona persona) async {
// Ottieni un riferimento al database.
final db = await database;
// Inserisci la Persona nella tabella corretta. Puoi anche specificare
// il `conflictAlgorithm` da utilizzare in caso la persona sia inserita due volte.
//
// In questo caso, sostituisci tutti i dati precedenti.
await db.insert(
'persone',
persona.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
// Crea una Persona e aggiungila alla tabella delle persone
var luca = Persona(
id: 0,
nome: 'Luca',
eta: 30,
);
await insertPersona(luca);
Ora che una persona è memorizzata nel database, interroghiamo il database per una persona specifica o un elenco di tutte le persone. Ciò comporta due passaggi:
// Un metodo che recupera tutte le persone dalla tabella persone.
Future> persone() async {
// Ottieni un riferimento al database.
final db = await database;
// Esegui una query nella tabella per tutte le Persone.
final List
// Utilizza il metodo indicato sopra per recuperare tutte le persone.
print(await persone());
// Stampa un elenco che include Luca.
Dopo aver inserito le informazioni nel database, potresti voler aggiornare tali informazioni in un secondo momento. Puoi farlo usando il metodo update() dalla libreria sqflite.
Ciò comporta due passaggi:
Future updatePersona(Persona persona) async {
// Ottieni un riferimento al database.
final db = await database;
// Aggiorna la persona.
await db.update(
'persone',
persona.toMap(),
// Assicurati che la persona abbia un ID corrispondente.
where: 'id = ?',
// Passa l’ ID della Persona come whereArg per evitare SQL injection.
whereArgs: [persona.id],
);
}
// Aggiorna l’età di Luca e salvala nel database.
luca = Persona(
id: luca.id,
nome: luca.nome,
eta: luca.eta + 7,
);
await updatePersona(luca);
// Stampa i risultati aggiornati.
print(await persone()); // Stampa Luca con l’eta di 37.
Avvertenza: usa sempre whereArgs per passare argomenti a un'istruzione where. Questo aiuta a salvaguardare dagli attacchi SQL injection.
Non utilizzare l'interpolazione di stringhe, ad esempio where: "id = ${persona.id}"!
Oltre a inserire e aggiornare le informazioni sulle persone, possiamo anche rimuovere le persone dal database. Per eliminare i dati, utilizzare il metodo delete() dalla libreria sqflite.
In questa sezione, creiamo una funzione che prenda un ID ed elimini la persona con un ID corrispondente dal database. Per fare in modo che funzioni, è necessario fornire una clausola where per limitare l'eliminazione dei record.
Future deletePerson(int id) async {
// Ottieni un riferimento al database.
final db = await database;
// Rimuovi la Persona dal database.
await db.delete(
'persone',
// Utilizza una clausola `where` per eliminare dal db una persona specifica
where: 'id = ?',
// Passa l’id della Persona come whereArg per prevenire SQL injection.
whereArgs: [id],
);
}
Contattami se hai bisogno di un programmatore Flutter per il tuo progetto o la tua azienda
Per eseguire l'esempio:
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
void main() async {
// Evita errori causati da upgrade di Flutter.
// È necessario importare 'package:flutter/widgets.dart'
WidgetsFlutterBinding.ensureInitialized();
// Apri il database e memorizza il riferimento.
final database = openDatabase(
// Imposta il percorso del database. Nota: utilizzare la funzione ‘join’ dal
// pacchetto ‘path’ è il modo migliore per assicurarsi che il percorso sia
// corretto per ogni piattaforma
join(await getDatabasesPath(), 'database_persone.db'),
// Quando il database viene creato per la prima volta, crea una tabella per memorizzare le persone.
onCreate: (db, version) {
// Esegui il comando CREATE TABLE sul database.
return db.execute(
'CREATE TABLE persone(id INTEGER PRIMARY KEY, nome TEXT, eta INTEGER)',
);
},
// Imposta la versione. Questo esegue la funzione onCreate e fornisce un percorso per eseguire upgrade e downgrade del database.
version: 1,
);
// Definisci una funzione che inserisce le persone nel database
Future<void> insertPersona(Persona persona) async {
// Ottieni un riferimento al database.
final db = await database;
// Inserisci la Persona nella tabella corretta. Puoi anche specificare
// il `conflictAlgorithm` da utilizzare in caso la persona sia inserita due volte.
//
// In questo caso, sostituisci tutti i dati precedenti.
await db.insert(
'persone',
persona.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
// Un metodo che recupera tutte le persone dalla tabella persone.
Future<List<Persona>> persone() async {
// Ottieni un riferimento al database.
final db = await database;
// Esegui una query nella tabella per tutte le Persone.
final List<Map<String, dynamic>> maps = await db.query('persone');
// Converti la List<Map<String, dynamic> in List<Persona>.
return List.generate(maps.length, (i) {
return Persona(
id: maps[i]['id'],
nome: maps[i]['nome'],
eta: maps[i]['eta'],
);
});
}
Future<void> updatePersona(Persona persona) async {
// Ottieni un riferimento al database.
final db = await database;
// Aggiorna la persona.
await db.update(
'persone',
persona.toMap(),
// Assicurati che la persona abbia un ID corrispondente.
where: 'id = ?',
// Passa l’ ID della Persona come whereArg per evitare SQL injection.
whereArgs: [persona.id],
);
}
Future<void> deletePerson(int id) async {
// Ottieni un riferimento al database.
final db = await database;
// Rimuovi la Persona dal database.
await db.delete(
'persone',
// Utilizza una clausola `where` per eliminare dal db una persona specifica
where: 'id = ?',
// Passa l’id della Persona come whereArg per prevenire SQL injection.
whereArgs: [id],
);
}
// Crea una Persona e aggiungila alla tabella delle persone
var luca = Persona(
id: 0,
nome: 'Luca',
eta: 30,
);
await insertPersona(luca);
// Utilizza il metodo indicato sopra per recuperare tutte le persone.
print(await persone());
// Stampa un elenco che include Luca.
// Aggiorna l’età di Luca e salvala nel database.
luca = Persona(
id: luca.id,
nome: luca.nome,
eta: luca.eta + 7,
);
await updatePersona(luca);
// Stampa i risultati aggiornati.
print(await persone()); // Stampa Luca con l’eta di 37.
// Rimuovi Luca dal database.
await deletePerson(luca.id);
// Stampa l'elenco delle persone (vuoto).
print(await persone());
}
class Persona {
final int id;
final String nome;
final int eta;
Persona({
required this.id,
required this.nome,
required this.eta,
});
// Converti una Persona in una Map. Le chiavi devono essere uguali ai nomi delle
//colonne nel database.
Map<String, dynamic> toMap() {
return {
'id': id,
'nome': nome,
'eta': eta,
};
}
// Implementa toString per rendere piu semplice visualizzare informazioni su
// ogni persona quando viene utilizzato il comando print.
@override
String toString() {
return 'Persona{id: $id, nome: $nome, eta: $eta}';
}
}