Floor — qué es, ORM sobre SQLite en Flutter

Autor: IT Sectr Publicado: 2026-03-13 Tiempo de lectura: 9 min

Floor — ORM (Object-Relational Mapping) para Flutter, que proporciona una capa tipada sobre SQLite. A diferencia de las consultas SQLite sin procesar, Floor genera clases DAO a partir de modelos Dart anotados. Según Pub.dev, 2024, Floor se utiliza en más de 3500 proyectos Flutter y se encuentra entre las tres soluciones ORM más populares para el almacenamiento local de datos junto con drift y hive.

Puntos Clave

  • Floor — ORM sobre SQLite con generación de código de DAO y Entity mediante anotaciones
  • Seguridad de tipos — las consultas se verifican en tiempo de compilación, eliminando errores SQL en tiempo de ejecución
  • Patrón DAO — Data Access Object encapsula consultas SQL en métodos Dart
  • Migraciones — soporte integrado para versionado de esquemas SQLite
  • Reactividad — consultas Flow mediante Stream para actualización automática de la UI

¿Qué es Floor?

Floor es una biblioteca ORM para Flutter y Dart construida sobre SQLite. Utiliza anotaciones para describir entidades (Entity), Data Access Objects (DAO) y la base de datos (Database). La generación de código se realiza mediante build_runner y floor_generator — el compilador crea implementaciones DAO y una clase gestora de base de datos. A diferencia de sqflite sin procesar, Floor elimina por completo la necesidad de conversión manual de ResultSet a objetos Dart, mapeando automáticamente las columnas a los campos Entity mediante reflexión de tipos.

Floor sigue el patrón Repository + DAO familiar para los desarrolladores Android por Room. Cada tabla está representada por una clase Dart con la anotación @Entity, las consultas SQL se agrupan en interfaces con la anotación @dao, y la base de datos se ensambla en una clase abstracta con @Database. Este enfoque separa estrictamente el modelo de datos de la lógica de consultas.

Según Flutter Pulse (2023), Floor se elige en el 28% de los proyectos Flutter que requieren una base de datos local. Las principales razones para elegirlo son la familiaridad con SQL (no es necesario aprender un nuevo lenguaje de consultas) y la verificación de consultas en tiempo de compilación. Además, Floor genera código legible que es fácil de depurar en comparación con ORM más abstractos con DSL personalizados, lo que reduce la barrera de entrada para nuevos desarrolladores en el equipo.

Arquitectura de Floor

Floor consta de tres capas: Entity (modelo de tabla), DAO (interfaz de consultas) y Database (punto de entrada). El generador crea implementaciones _$_Entity para el mapeo de campos y _$_Dao para ejecutar SQL. Cuando cambian Entity o DAO, basta con reiniciar build_runner — el código se actualiza automáticamente. Para la migración entre versiones de esquema, Floor utiliza números de versión secuenciales, garantizando la integridad de los datos al actualizar la aplicación en los dispositivos de los usuarios.

¿Cómo funciona Floor en Flutter?

Floor utiliza SQLite a través del paquete sqflite para compilaciones nativas y sqlite3 para escritorio y web. Cuando la aplicación se inicia, Floor crea o abre el archivo SQLite, aplica migraciones y prepara los métodos DAO para ejecutar consultas. Todas las operaciones se realizan de forma asíncrona mediante Future y Stream.

La generación de código en Floor funciona de la siguiente manera: el analizador lee las anotaciones de los archivos fuente, crea un AST (Árbol de Sintaxis Abstracta) de modelos y consultas, luego genera archivos Dart con el prefijo _$. El código generado incluye mapeadores ResultSet → Entity y viceversa.

Seguridad de hilos

Floor trabaja con SQLite en un único isolate. Todas las consultas se ejecutan de forma asíncrona, pero las escrituras concurrentes se bloquean a nivel de SQLite. Para transacciones, se utiliza la anotación @transaction, que garantiza la atomicidad de un grupo de consultas y la reversión en caso de error.

Floor vs Drift: comparación de ORM para Flutter

Tanto Floor como Drift son ORM sobre SQLite, pero difieren en filosofía. Floor está más cerca de Room de Android, Drift es más reactivo con API Stream integrada y compilación de consultas mediante archivos SQL. La elección entre ellos depende de la experiencia del equipo y la reactividad requerida.

CaracterísticaFloorDrift
Tipo de consultasCadenas SQL en @QueryMétodos Dart + archivos sql
Generación de códigofloor_generator (build_runner)drift_dev (build_runner)
ReactividadStream desde DAOAPI Stream integrada + auto-actualización
ComplejidadBaja (SQL familiar)Media (DSL propio)
MigracionesScripts SQL manualesAutomáticas + manuales
CompatibilidadAndroid, iOS, macOSAndroid, iOS, Web, macOS, Linux

Cuándo elegir Floor

Floor es la elección para equipos ya familiarizados con SQL y Android Room. Si los desarrolladores están acostumbrados a escribir consultas SQL manualmente y quieren una envoltura mínima sobre SQLite — Floor proporciona tipificación sin aprender un nuevo DSL. También es más fácil de depurar ya que el código generado es legible y predecible.

Cuándo es mejor Drift

Drift ofrece una reactividad más potente y soporta más plataformas. Si la aplicación usa activamente Stream para actualizar la UI, requiere consultas complejas con JOIN y subconsultas o se dirige a web — Drift es preferible. Sin embargo, su barrera de entrada es mayor debido a la necesidad de aprender su propio DSL.

Ejemplos de código con Floor

Floor se construye alrededor de anotaciones. A continuación se muestra un ejemplo completo de Entity, DAO y Database para una aplicación de lista de tareas. Después de ejecutar build_runner, las clases generadas están listas para usar.

Definición de Entity y DAO

La clase TaskEntity con la anotación @Entity se mapea a la tabla task. Un campo con @primaryKey se convierte en la clave primaria. La interfaz TaskDao contiene métodos para operaciones con la tabla — cada método está anotado con @Query, @Insert, @Update o @Delete.

dart
@entity
class TaskEntity {
    @PrimaryKey(autoGenerate: true)
    final int id;
    final String title;
    final bool isCompleted;
    final int priority;

    TaskEntity({this.id, required this.title,
        this.isCompleted = false, this.priority = 0});
}

@dao
abstract class TaskDao {
    @Query('SELECT * FROM TaskEntity ORDER BY priority DESC')
    Future<List<TaskEntity>> getAllTasks();

    @Insert
    Future<int> insertTask(TaskEntity task);

    @Update
    Future<void> updateTask(TaskEntity task);

    @Query('SELECT * FROM TaskEntity WHERE isCompleted = :status')
    Stream<List<TaskEntity>> watchTasks(bool status);
}

Inicialización de la base de datos

Una clase abstracta con la anotación @Database vincula Entity y DAO. El método databaseBuilder crea una instancia de base de datos. Después de llamar a build, la base de datos está lista: Floor abre el archivo SQLite, aplica migraciones y devuelve el DAO para trabajar.

dart
@Database(version: 1, entities: [TaskEntity])
abstract class AppDatabase extends FloorDatabase {
    TaskDao get taskDao;
}

// Uso
final database = await $FloorAppDatabase.databaseBuilder('app.db').build();
final taskDao = database.taskDao;
final tasks = await taskDao.getAllTasks();

Consultas reactivas mediante Stream

Floor soporta la devolución de Stream desde métodos DAO. Ante cualquier cambio en la tabla, el Stream emite una nueva lista. Esto se integra con StreamBuilder en Flutter — la UI se actualiza automáticamente cuando se añaden, modifican o eliminan registros.

dart
@Query('SELECT * FROM TaskEntity ORDER BY priority DESC')
Stream<List<TaskEntity>> watchAllTasks();

// En widget Flutter
StreamBuilder<List<TaskEntity>>(
    stream: taskDao.watchAllTasks(),
    builder: (context, snapshot) {
        final tasks = snapshot.data ?? [];
        return ListView.builder(
            itemCount: tasks.length,
            itemBuilder: (_, i) => TaskTile(tasks[i]),
        );
    },
)

Migraciones y versionado en Floor

Floor soporta el versionado de bases de datos mediante el parámetro version en la anotación @Database. Cuando cambia Entity (añadir o eliminar campos), es necesario incrementar la versión y añadir una migración. Una migración es una función Dart que recibe una transacción y ejecuta consultas SQL ALTER TABLE.

Ejemplo de migración

Supongamos que en la versión 2 añadimos un campo dueDate a TaskEntity. La migración se realiza mediante una consulta SQL ALTER TABLE. Si no se especifica una migración, Floor llama a MigrationStrategy donde se puede establecer un fallback (por ejemplo, recrear la tabla con pérdida de datos).

Pruebas de consultas Floor

Floor no proporciona un framework mock integrado, pero la base de datos se puede reemplazar fácilmente en las pruebas. Cree un inMemoryDatabaseBuilder — crea una base de datos SQLite en memoria idéntica en esquema a producción. Después de cada prueba, limpie los datos mediante deleteDatabase para aislar los escenarios de prueba.

Transacciones y operaciones por lotes en Floor

Floor soporta transacciones mediante la anotación @transaction en métodos DAO. Dentro de una transacción, se ejecutan múltiples consultas secuencialmente con garantía de reversión en caso de error. La inserción por lotes mediante @Insert con un parámetro List optimiza la inserción de múltiples registros en una sola llamada — esto es varias veces más rápido que insertar un registro a la vez en un bucle. Para operaciones masivas, use inserciones por lotes de 100–200 registros: este es el equilibrio óptimo entre velocidad de ejecución y consumo de RAM en dispositivos móviles con recursos limitados.

dart
final migration1to2 = Migration(1, 2, (database) async {
    await database.execute(
        'ALTER TABLE TaskEntity ADD COLUMN dueDate TEXT'
    );
});

final database = await $FloorAppDatabase.databaseBuilder('app.db')
    .addMigrations([migration1to2])
    .build();

Preguntas Frecuentes

¿En qué se diferencia Floor de sqflite sin procesar?

sqflite requiere escritura manual de consultas SQL y mapeo de ResultSet a objetos. Floor genera este código automáticamente: usted describe Entity y DAO, y los métodos tipificados devuelven objetos Dart listos para usar. Floor también verifica las consultas SQL en tiempo de compilación mediante anotaciones.

¿Soporta Floor relaciones entre tablas?

Floor no tiene anotaciones integradas para relaciones (ForeignKey, @Relation) como Room. Las relaciones se implementan mediante consultas SQL JOIN manuales en @Query. Para esquemas relacionales complejos, considere Drift con su soporte integrado de relaciones.

¿Cómo depurar consultas SQL de Floor?

Floor permite habilitar un callback al crear DatabaseBuilder — recibe una instancia de sqflite.Database en la que puede conectar un registrador. Alternativamente, use floor_doctor para visualizar el esquema y los datos en modo dev.

¿Se puede usar Floor para compilaciones web?

Floor usa sqflite, que no funciona en un entorno web. Para web, se requiere una compilación separada con sqlite3 mediante WASM. En la versión actual, Floor soporta oficialmente Android, iOS y macOS. Para web, use Drift con el adaptador sqlite3.

¿Cómo funciona el almacenamiento en caché de consultas en Floor?

Floor no tiene almacenamiento en caché integrado — cada consulta se ejecuta contra SQLite. Para almacenar en caché consultas repetidas, use una capa Repository con caché en memoria (por ejemplo, dart_cache). Floor solo genera código para trabajar con SQLite sin añadir sobrecarga.

Resumen

  • Floor — ORM sobre SQLite con generación de código de Entity, DAO y Database mediante anotaciones
  • Seguridad de tipos — las consultas SQL se verifican en tiempo de compilación mediante la anotación @Query
  • Patrón DAO — las consultas SQL se encapsulan en métodos Dart, separando el modelo de la lógica
  • Migraciones — versionado de esquemas mediante Migration con ALTER TABLE manual
  • Reactividad — Stream desde DAO para actualización automática de la UI ante cambios
  • Limitaciones — sin relaciones integradas, no soporta compilaciones web
  • Recomendación — elija Floor para proyectos Flutter donde el equipo esté familiarizado con SQL y el enfoque Room

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también