Introducción

SQLite es una biblioteca de software que proporciona una base de datos relacional ligera y autónoma. Es una opción popular para el almacenamiento local en aplicaciones móviles debido a su simplicidad y eficiencia. En este tema, aprenderás cómo integrar SQLite en tu aplicación Flutter para gestionar datos de manera persistente.

Objetivos de Aprendizaje

  • Comprender qué es SQLite y por qué es útil en aplicaciones móviles.
  • Configurar SQLite en un proyecto Flutter.
  • Crear, leer, actualizar y eliminar (CRUD) datos en una base de datos SQLite.
  • Manejar errores comunes y optimizar el rendimiento de las operaciones de base de datos.

Configuración de SQLite en Flutter

Para utilizar SQLite en Flutter, usaremos el paquete sqflite. Sigue estos pasos para configurarlo:

  1. Agregar Dependencias: Abre el archivo pubspec.yaml y añade las siguientes dependencias:

    dependencies:
      flutter:
        sdk: flutter
      sqflite: ^2.0.0+3
      path: ^1.8.0
    
  2. Instalar Dependencias: Ejecuta el comando flutter pub get para instalar las dependencias.

  3. Importar Paquetes: Importa los paquetes necesarios en tu archivo Dart:

    import 'package:sqflite/sqflite.dart';
    import 'package:path/path.dart';
    

Creación de la Base de Datos

Paso 1: Inicializar la Base de Datos

Crea una función para inicializar la base de datos. Esta función abrirá la base de datos y ejecutará una consulta SQL para crear una tabla si no existe.

Future<Database> initializeDB() async {
  String path = await getDatabasesPath();
  return openDatabase(
    join(path, 'example.db'),
    onCreate: (database, version) async {
      await database.execute(
        "CREATE TABLE items(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, quantity INTEGER NOT NULL)",
      );
    },
    version: 1,
  );
}

Paso 2: Insertar Datos

Crea una función para insertar datos en la tabla.

Future<void> insertItem(Database db, String name, int quantity) async {
  await db.insert(
    'items',
    {'name': name, 'quantity': quantity},
    conflictAlgorithm: ConflictAlgorithm.replace,
  );
}

Paso 3: Leer Datos

Crea una función para leer datos de la tabla.

Future<List<Map<String, dynamic>>> retrieveItems(Database db) async {
  final List<Map<String, dynamic>> queryResult = await db.query('items');
  return queryResult;
}

Paso 4: Actualizar Datos

Crea una función para actualizar datos en la tabla.

Future<void> updateItem(Database db, int id, String name, int quantity) async {
  await db.update(
    'items',
    {'name': name, 'quantity': quantity},
    where: "id = ?",
    whereArgs: [id],
  );
}

Paso 5: Eliminar Datos

Crea una función para eliminar datos de la tabla.

Future<void> deleteItem(Database db, int id) async {
  await db.delete(
    'items',
    where: "id = ?",
    whereArgs: [id],
  );
}

Ejemplo Completo

A continuación, se muestra un ejemplo completo que integra todas las funciones anteriores en una aplicación Flutter.

import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  Database? _database;

  @override
  void initState() {
    super.initState();
    initializeDB().then((db) {
      setState(() {
        _database = db;
      });
    });
  }

  Future<Database> initializeDB() async {
    String path = await getDatabasesPath();
    return openDatabase(
      join(path, 'example.db'),
      onCreate: (database, version) async {
        await database.execute(
          "CREATE TABLE items(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, quantity INTEGER NOT NULL)",
        );
      },
      version: 1,
    );
  }

  Future<void> insertItem(String name, int quantity) async {
    await _database?.insert(
      'items',
      {'name': name, 'quantity': quantity},
      conflictAlgorithm: ConflictAlgorithm.replace,
    );
    setState(() {});
  }

  Future<List<Map<String, dynamic>>> retrieveItems() async {
    final List<Map<String, dynamic>> queryResult = await _database!.query('items');
    return queryResult;
  }

  Future<void> updateItem(int id, String name, int quantity) async {
    await _database?.update(
      'items',
      {'name': name, 'quantity': quantity},
      where: "id = ?",
      whereArgs: [id],
    );
    setState(() {});
  }

  Future<void> deleteItem(int id) async {
    await _database?.delete(
      'items',
      where: "id = ?",
      whereArgs: [id],
    );
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('SQLite Example'),
      ),
      body: FutureBuilder(
        future: retrieveItems(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            return Center(child: Text('Error: ${snapshot.error}'));
          } else {
            final items = snapshot.data as List<Map<String, dynamic>>;
            return ListView.builder(
              itemCount: items.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text(items[index]['name']),
                  subtitle: Text('Quantity: ${items[index]['quantity']}'),
                  trailing: IconButton(
                    icon: Icon(Icons.delete),
                    onPressed: () {
                      deleteItem(items[index]['id']);
                    },
                  ),
                );
              },
            );
          }
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          insertItem('Item ${DateTime.now()}', 1);
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

Ejercicios Prácticos

  1. Ejercicio 1: Modifica la aplicación para que permita actualizar la cantidad de un ítem existente.
  2. Ejercicio 2: Añade una funcionalidad para buscar ítems por nombre.
  3. Ejercicio 3: Implementa una función para ordenar los ítems por cantidad.

Soluciones

Ejercicio 1: Modificar la cantidad de un ítem existente.

// Añadir un botón de edición en cada ListTile
trailing: Row(
  mainAxisSize: MainAxisSize.min,
  children: [
    IconButton(
      icon: Icon(Icons.edit),
      onPressed: () {
        updateItem(items[index]['id'], items[index]['name'], items[index]['quantity'] + 1);
      },
    ),
    IconButton(
      icon: Icon(Icons.delete),
      onPressed: () {
        deleteItem(items[index]['id']);
      },
    ),
  ],
),

Ejercicio 2: Buscar ítems por nombre.

Future<List<Map<String, dynamic>>> searchItems(String name) async {
  final List<Map<String, dynamic>> queryResult = await _database!.query(
    'items',
    where: "name LIKE ?",
    whereArgs: ['%$name%'],
  );
  return queryResult;
}

Ejercicio 3: Ordenar los ítems por cantidad.

Future<List<Map<String, dynamic>>> retrieveItemsOrdered() async {
  final List<Map<String, dynamic>> queryResult = await _database!.query(
    'items',
    orderBy: "quantity DESC",
  );
  return queryResult;
}

Conclusión

En esta sección, has aprendido cómo integrar SQLite en una aplicación Flutter para realizar operaciones CRUD. SQLite es una herramienta poderosa para el almacenamiento local y es esencial para aplicaciones que requieren persistencia de datos. Asegúrate de manejar adecuadamente los errores y optimizar las consultas para mantener un rendimiento óptimo.

Curso de Desarrollo con Flutter

Módulo 1: Introducción a Flutter

Módulo 2: Conceptos Básicos de Programación en Dart

Módulo 3: Widgets en Flutter

Módulo 4: Gestión de Estado

Módulo 5: Navegación y Enrutamiento

Módulo 6: Redes y APIs

Módulo 7: Persistencia y Almacenamiento

Módulo 8: Conceptos Avanzados de Flutter

Módulo 9: Pruebas y Depuración

Módulo 10: Despliegue y Mantenimiento

Módulo 11: Flutter para Web y Escritorio

© Copyright 2024. Todos los derechos reservados