[{"data":1,"prerenderedAt":68},["ShallowReactive",2],{"tutorial-salvare-dati-strutturati-in-flutter-con-il-database-sqlite-e-sqflite":3,"comments-tutorial-salvare-dati-strutturati-in-flutter-con-il-database-sqlite-e-sqflite":67},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"video_url":10,"difficulty":11,"estimated_minutes":12,"flutter_version":13,"status":14,"published_at":15,"meta_title":16,"meta_description":17,"category":18,"author":22,"steps":24},7,"Salvare dati strutturati in Flutter con il database SQLite e sqflite","salvare-dati-strutturati-in-flutter-con-il-database-sqlite-e-sqflite","Impara a integrare un database locale SQLite nelle tue app Flutter usando il pacchetto sqflite: creazione tabelle, operazioni CRUD e pattern repository.","Quando un'app Flutter deve gestire molti dati strutturati e relazioni, `shared_preferences` non basta più. In questi casi un vero database relazionale come **SQLite** è la scelta ideale.\n\nIn questo tutorial vedremo come usare il pacchetto [`sqflite`](https:\u002F\u002Fpub.dev\u002Fpackages\u002Fsqflite) per creare un database locale, definire una tabella e implementare le operazioni **CRUD** (Create, Read, Update, Delete) seguendo un pattern pulito e riutilizzabile.\n\nCostruiremo un piccolo gestore di **note** persistenti.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F085a7a07-e971-43ae-bba8-b88d55d4e623.jpg",null,"intermediate",40,"3.x","published","2026-06-11T04:30:39+00:00","SQLite in Flutter con sqflite: guida CRUD","Tutorial pratico su come usare SQLite in Flutter con sqflite: creazione tabelle, CRUD e pattern repository per dati locali persistenti.",{"id":19,"name":20,"slug":21},1,"Guide","guide",{"id":19,"name":23},"Flutter Bot",[25,32,40,47,54,61],{"id":26,"position":19,"title":27,"body":28,"code_snippet":29,"code_language":30,"expected_result":31,"demo_url":10,"video_url":10},50,"Aggiungere le dipendenze","Aggiungiamo `sqflite` per il database e `path` per costruire in modo sicuro il percorso del file su ogni piattaforma.\n\nEsegui da terminale:\n\n```bash\nflutter pub add sqflite path\n```\n\nIn alternativa modifica manualmente il file `pubspec.yaml` come mostrato nello snippet e poi lancia `flutter pub get`.","dependencies:\n  flutter:\n    sdk: flutter\n  sqflite: ^2.3.0\n  path: ^1.9.0","yaml","Le dipendenze sqflite e path risultano installate senza errori.",{"id":33,"position":34,"title":35,"body":36,"code_snippet":37,"code_language":38,"expected_result":39,"demo_url":10,"video_url":10},51,2,"Creare il modello dati Note","Definiamo una classe `Note` con i metodi `toMap` e `fromMap` per convertire tra oggetto Dart e riga del database. SQLite memorizza valori semplici, quindi mappiamo ogni campo a una colonna.\n\nUsiamo un `id` nullable perché viene generato automaticamente dal database all'inserimento.","class Note {\n  final int? id;\n  final String title;\n  final String content;\n  final DateTime createdAt;\n\n  Note({\n    this.id,\n    required this.title,\n    required this.content,\n    required this.createdAt,\n  });\n\n  Map\u003CString, Object?> toMap() {\n    return {\n      'id': id,\n      'title': title,\n      'content': content,\n      'created_at': createdAt.toIso8601String(),\n    };\n  }\n\n  factory Note.fromMap(Map\u003CString, Object?> map) {\n    return Note(\n      id: map['id'] as int?,\n      title: map['title'] as String,\n      content: map['content'] as String,\n      createdAt: DateTime.parse(map['created_at'] as String),\n    );\n  }\n}","dart","La classe Note è pronta per essere serializzata e deserializzata dal database.",{"id":41,"position":42,"title":43,"body":44,"code_snippet":45,"code_language":38,"expected_result":46,"demo_url":10,"video_url":10},52,3,"Inizializzare il database e creare la tabella","Creiamo una classe `DatabaseHelper` che gestisce l'apertura del database come singleton. Il database viene aperto una sola volta e riutilizzato.\n\nNella callback `onCreate` definiamo lo schema della tabella `notes`. Il parametro `version` è importante: se in futuro modifichi lo schema potrai gestire le migrazioni con `onUpgrade`.","import 'package:path\u002Fpath.dart';\nimport 'package:sqflite\u002Fsqflite.dart';\n\nclass DatabaseHelper {\n  DatabaseHelper._privateConstructor();\n  static final DatabaseHelper instance = DatabaseHelper._privateConstructor();\n\n  static Database? _database;\n\n  Future\u003CDatabase> get database async {\n    _database ??= await _initDatabase();\n    return _database!;\n  }\n\n  Future\u003CDatabase> _initDatabase() async {\n    final dbPath = await getDatabasesPath();\n    final path = join(dbPath, 'notes.db');\n\n    return openDatabase(\n      path,\n      version: 1,\n      onCreate: _onCreate,\n    );\n  }\n\n  Future\u003Cvoid> _onCreate(Database db, int version) async {\n    await db.execute('''\n      CREATE TABLE notes(\n        id INTEGER PRIMARY KEY AUTOINCREMENT,\n        title TEXT NOT NULL,\n        content TEXT NOT NULL,\n        created_at TEXT NOT NULL\n      )\n    ''');\n  }\n}","Al primo accesso viene creato il file notes.db con la tabella notes.",{"id":48,"position":49,"title":50,"body":51,"code_snippet":52,"code_language":38,"expected_result":53,"demo_url":10,"video_url":10},53,4,"Implementare le operazioni CRUD","Creiamo un `NoteRepository` che espone metodi chiari per inserire, leggere, aggiornare ed eliminare le note. Questo separa la logica di accesso ai dati dal resto dell'app.\n\nNota l'uso di `conflictAlgorithm` per la `insert` e di `whereArgs` per evitare SQL injection.","class NoteRepository {\n  final DatabaseHelper _dbHelper = DatabaseHelper.instance;\n\n  Future\u003Cint> insertNote(Note note) async {\n    final db = await _dbHelper.database;\n    return db.insert(\n      'notes',\n      note.toMap()..remove('id'),\n      conflictAlgorithm: ConflictAlgorithm.replace,\n    );\n  }\n\n  Future\u003CList\u003CNote>> getAllNotes() async {\n    final db = await _dbHelper.database;\n    final maps = await db.query('notes', orderBy: 'created_at DESC');\n    return maps.map((m) => Note.fromMap(m)).toList();\n  }\n\n  Future\u003Cint> updateNote(Note note) async {\n    final db = await _dbHelper.database;\n    return db.update(\n      'notes',\n      note.toMap(),\n      where: 'id = ?',\n      whereArgs: [note.id],\n    );\n  }\n\n  Future\u003Cint> deleteNote(int id) async {\n    final db = await _dbHelper.database;\n    return db.delete('notes', where: 'id = ?', whereArgs: [id]);\n  }\n}","Il repository permette di eseguire tutte le operazioni CRUD sulle note.",{"id":55,"position":56,"title":57,"body":58,"code_snippet":59,"code_language":38,"expected_result":60,"demo_url":10,"video_url":10},54,5,"Mostrare e gestire le note nella UI","Colleghiamo il repository a una semplice schermata. Carichiamo le note in `initState`, le mostriamo in una `ListView` e aggiungiamo un pulsante per inserire una nota di esempio.\n\nDopo ogni operazione di scrittura ricarichiamo la lista per aggiornare l'interfaccia.","class NotesScreen extends StatefulWidget {\n  const NotesScreen({super.key});\n\n  @override\n  State\u003CNotesScreen> createState() => _NotesScreenState();\n}\n\nclass _NotesScreenState extends State\u003CNotesScreen> {\n  final NoteRepository _repo = NoteRepository();\n  List\u003CNote> _notes = [];\n\n  @override\n  void initState() {\n    super.initState();\n    _loadNotes();\n  }\n\n  Future\u003Cvoid> _loadNotes() async {\n    final notes = await _repo.getAllNotes();\n    setState(() => _notes = notes);\n  }\n\n  Future\u003Cvoid> _addSampleNote() async {\n    await _repo.insertNote(Note(\n      title: 'Nota ${_notes.length + 1}',\n      content: 'Contenuto di esempio',\n      createdAt: DateTime.now(),\n    ));\n    await _loadNotes();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('Le mie note')),\n      body: ListView.builder(\n        itemCount: _notes.length,\n        itemBuilder: (context, index) {\n          final note = _notes[index];\n          return ListTile(\n            title: Text(note.title),\n            subtitle: Text(note.content),\n            trailing: IconButton(\n              icon: const Icon(Icons.delete),\n              onPressed: () async {\n                await _repo.deleteNote(note.id!);\n                await _loadNotes();\n              },\n            ),\n          );\n        },\n      ),\n      floatingActionButton: FloatingActionButton(\n        onPressed: _addSampleNote,\n        child: const Icon(Icons.add),\n      ),\n    );\n  }\n}","L'app mostra l'elenco delle note salvate e permette di aggiungerle ed eliminarle in modo persistente.",{"id":62,"position":63,"title":64,"body":65,"code_snippet":10,"code_language":38,"expected_result":66,"demo_url":10,"video_url":10},55,6,"Verificare la persistenza dei dati","Per confermare che SQLite memorizzi davvero i dati su disco:\n\n1. Avvia l'app e crea alcune note con il pulsante `+`.\n2. **Chiudi completamente** l'app (non solo in background).\n3. Riaprila: le note create devono essere ancora presenti.\n\nA differenza di una lista in memoria, i dati sopravvivono al riavvio perché sono salvati nel file `notes.db`.\n\n> Suggerimento: se modifichi lo schema della tabella durante lo sviluppo, disinstalla l'app dal dispositivo oppure incrementa il parametro `version` e implementa `onUpgrade`, altrimenti vedrai errori di colonna mancante.","Le note restano salvate anche dopo la chiusura e la riapertura dell'app, confermando la persistenza tramite SQLite.",[],1781247855837]