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 é 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.
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.
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.
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.
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ística | Floor | Drift |
|---|---|---|
| Tipo de consultas | Strings SQL em @Query | Métodos Dart + arquivos sql |
| Geração de código | floor_generator (build_runner) | drift_dev (build_runner) |
| Reatividade | Stream do DAO | API Stream integrada + auto-atualização |
| Complexidade | Baixa (SQL familiar) | Média (DSL próprio) |
| Migrações | Scripts SQL manuais | Automáticas + manuais |
| Compatibilidade | Android, iOS, macOS | Android, iOS, Web, macOS, Linux |
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.
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.
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.
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.
@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);
}
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.
@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();
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.
@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]),
);
},
)
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.
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).
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.
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
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
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.
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.
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.
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.
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
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.
Leia também