Floor — o que é, ORM sobre SQLite no Flutter

Autor: IT Sectr Publicado: 2026-03-13 Tempo de leitura: 9 min

Floor — ORM (Object-Relational Mapping) para Flutter, que fornece uma camada tipada sobre SQLite. Ao contrário de consultas SQLite brutas, Floor gera classes DAO a partir de modelos Dart anotados. De acordo com Pub.dev, 2024, Floor é usado em mais de 3500 projetos Flutter e está entre as três soluções ORM mais populares para armazenamento local de dados junto com drift e hive.

Principais Pontos

  • Floor — ORM sobre SQLite com geração de código de DAO e Entity através de anotações
  • Segurança de tipos — consultas são verificadas em tempo de compilação, eliminando erros SQL em tempo de execução
  • Padrão DAO — Data Access Object encapsula consultas SQL em métodos Dart
  • Migrações — suporte integrado para versionamento de esquema SQLite
  • Reatividade — consultas Flow via Stream para atualização automática da UI

O que é Floor?

Floor é uma biblioteca ORM para Flutter e Dart construída sobre SQLite. Ela usa anotações para descrever entidades (Entity), Data Access Objects (DAO) e o banco de dados (Database). A geração de código é realizada via build_runner e floor_generator — o compilador cria implementações DAO e uma classe gerenciadora de banco de dados. Ao contrário do sqflite bruto, Floor elimina completamente a necessidade de conversão manual de ResultSet para objetos Dart, mapeando automaticamente colunas para campos Entity através de reflexão de tipos.

Floor segue o padrão Repository + DAO familiar aos desenvolvedores Android pelo Room. Cada tabela é representada por uma classe Dart com a anotação @Entity, consultas SQL são agrupadas em interfaces com a anotação @dao, e o banco de dados é montado em uma classe abstrata com @Database. Esta abordagem separa estritamente o modelo de dados da lógica de consultas.

De acordo com Flutter Pulse (2023), Floor é escolhido em 28% dos projetos Flutter que exigem um banco de dados local. As principais razões para escolhê-lo são familiaridade com SQL (sem necessidade de aprender uma nova linguagem de consulta) e verificação de consultas em tempo de compilação. Além disso, Floor gera código legível que é fácil de depurar em comparação com ORMs mais abstratos com DSL personalizados, o que reduz a barreira de entrada para novos desenvolvedores na equipe.

Arquitetura do Floor

Floor consiste em três camadas: Entity (modelo de tabela), DAO (interface de consultas) e Database (ponto de entrada). O gerador cria implementações _$_Entity para mapeamento de campos e _$_Dao para executar SQL. Quando Entity ou DAO muda, basta reiniciar o build_runner — o código é atualizado automaticamente. Para migração entre versões de esquema, Floor usa números de versão sequenciais, garantindo a integridade dos dados ao atualizar o aplicativo nos dispositivos dos usuários.

Como o Floor funciona no Flutter?

Floor usa SQLite através do pacote sqflite para compilações nativas e sqlite3 para desktop e web. Quando o aplicativo inicia, Floor cria ou abre o arquivo SQLite, aplica migrações e prepara métodos DAO para executar consultas. Todas as operações são realizadas de forma assíncrona via Future e Stream.

A geração de código no Floor funciona da seguinte forma: o analisador lê anotações dos arquivos fonte, cria uma AST (Árvore de Sintaxe Abstrata) de modelos e consultas, então gera arquivos Dart com o prefixo _$. O código gerado inclui mapeadores ResultSet → Entity e vice-versa.

Segurança de threads

Floor trabalha com SQLite em um único isolate. Todas as consultas são executadas de forma assíncrona, mas escritas concorrentes são bloqueadas no nível SQLite. Para transações, a anotação @transaction é usada, garantindo atomicidade de um grupo de consultas e reversão em caso de erro.

Floor vs Drift: comparação de ORM para Flutter

Tanto Floor quanto Drift são ORMs sobre SQLite, mas diferem em filosofia. Floor é mais próximo do Room do Android, Drift é mais reativo com API Stream integrada e compilação de consultas via arquivos SQL. A escolha entre eles depende da experiência da equipe e da reatividade necessária.

CaracterísticaFloorDrift
Tipo de consultasStrings SQL em @QueryMétodos Dart + arquivos sql
Geração de códigofloor_generator (build_runner)drift_dev (build_runner)
ReatividadeStream do DAOAPI Stream integrada + auto-atualização
ComplexidadeBaixa (SQL familiar)Média (DSL próprio)
MigraçõesScripts SQL manuaisAutomáticas + manuais
CompatibilidadeAndroid, iOS, macOSAndroid, iOS, Web, macOS, Linux

Quando escolher Floor

Floor é a escolha para equipes já familiarizadas com SQL e Android Room. Se os desenvolvedores estão acostumados a escrever consultas SQL manualmente e querem um invólucro mínimo sobre SQLite — Floor fornece tipagem sem aprender um novo DSL. Também é mais fácil de depurar já que o código gerado é legível e previsível.

Quando Drift é melhor

Drift oferece reatividade mais poderosa e suporta mais plataformas. Se o aplicativo usa ativamente Stream para atualizar a UI, requer consultas complexas com JOIN e subconsultas ou tem como alvo a web — Drift é preferível. No entanto, sua barreira de entrada é maior devido à necessidade de aprender seu próprio DSL.

Exemplos de código com Floor

Floor é construído em torno de anotações. Abaixo está um exemplo completo de Entity, DAO e Database para um aplicativo de lista de tarefas. Após executar o build_runner, as classes geradas estão prontas para uso.

Definindo Entity e DAO

A classe TaskEntity com anotação @Entity mapeia para a tabela task. Um campo com @primaryKey torna-se a chave primária. A interface TaskDao contém métodos para operações de tabela — cada método é anotado com @Query, @Insert, @Update ou @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);
}

Inicialização do banco de dados

Uma classe abstrata com anotação @Database liga Entity e DAO. O método databaseBuilder cria uma instância do banco de dados. Após chamar build, o banco de dados está pronto: Floor abre o arquivo SQLite, aplica migrações e retorna o DAO para trabalho.

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 reativas via Stream

Floor suporta retornar Stream de métodos DAO. Em quaisquer mudanças na tabela, o Stream emite uma nova lista. Isso se integra com StreamBuilder no Flutter — a UI é atualizada automaticamente quando registros são adicionados, modificados ou excluídos.

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

// No 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]),
        );
    },
)

Migrações e versionamento no Floor

Floor suporta versionamento de banco de dados através do parâmetro version na anotação @Database. Quando Entity muda (adicionando ou removendo campos), você precisa incrementar a versão e adicionar uma migração. Uma migração é uma função Dart que recebe uma transação e executa consultas SQL ALTER TABLE.

Exemplo de migração

Suponha que na versão 2 adicionamos um campo dueDate ao TaskEntity. A migração é realizada via consulta SQL ALTER TABLE. Se uma migração não for especificada, Floor chama MigrationStrategy onde você pode definir um fallback (por exemplo, recriar a tabela com perda de dados).

Testando consultas Floor

Floor não fornece um framework mock integrado, mas o banco de dados pode ser facilmente substituído em testes. Crie um inMemoryDatabaseBuilder — ele cria um banco de dados SQLite em memória idêntico em esquema à produção. Após cada teste, limpe os dados via deleteDatabase para isolar cenários de teste.

Transações e operações em lote no Floor

Floor suporta transações via anotação @transaction em métodos DAO. Dentro de uma transação, múltiplas consultas são executadas sequencialmente com garantia de reversão em caso de erro. Inserção em lote via @Insert com um parâmetro List otimiza a inserção de múltiplos registros em uma única chamada — isso é várias vezes mais rápido do que inserir um registro de cada vez em um loop. Para operações em massa, use inserções em lote de 100–200 registros: este é o equilíbrio ideal entre velocidade de execução e consumo de RAM em dispositivos móveis com 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();

Perguntas Frequentes

Como o Floor é diferente do sqflite bruto?

sqflite requer escrita manual de consultas SQL e mapeamento de ResultSet para objetos. Floor gera esse código automaticamente: você descreve Entity e DAO, e métodos tipados retornam objetos Dart prontos para uso. Floor também verifica consultas SQL em tempo de compilação via anotações.

O Floor suporta relacionamentos entre tabelas?

Floor não possui anotações integradas para relacionamentos (ForeignKey, @Relation) como Room. Relacionamentos são implementados através de consultas SQL JOIN manuais em @Query. Para esquemas relacionais complexos, considere Drift com seu suporte integrado a relacionamentos.

Como depurar consultas SQL do Floor?

Floor permite habilitar um callback ao criar DatabaseBuilder — ele recebe uma instância de sqflite.Database na qual você pode anexar um logger. Alternativamente, use floor_doctor para visualizar esquema e dados em modo dev.

O Floor pode ser usado para compilações web?

Floor usa sqflite, que não funciona em ambiente web. Para web, é necessária uma compilação separada com sqlite3 via WASM. Na versão atual, Floor suporta oficialmente Android, iOS e macOS. Para web, use Drift com o adaptador sqlite3.

Como funciona o cache de consultas no Floor?

Floor não possui cache integrado — cada consulta é executada contra SQLite. Para armazenar em cache consultas repetidas, use uma camada Repository com cache em memória (por exemplo, dart_cache). Floor apenas gera código para trabalhar com SQLite sem adicionar sobrecarga sobre ele.

Resumo

  • Floor — ORM sobre SQLite com geração de código de Entity, DAO e Database via anotações
  • Segurança de tipos — consultas SQL são verificadas em tempo de compilação via anotação @Query
  • Padrão DAO — consultas SQL são encapsuladas em métodos Dart, separando modelo da lógica
  • Migrações — versionamento de esquema via Migration com ALTER TABLE manual
  • Reatividade — Stream do DAO para atualização automática da UI em mudanças
  • Limitações — sem relacionamentos integrados, não suporta compilações web
  • Recomendação — escolha Floor para projetos Flutter onde a equipe está familiarizada com SQL e a abordagem Room

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também