Floor — ORM (Object-Relational Mapping) voor Flutter, die een getypeerde laag bovenop SQLite biedt. In tegenstelling tot raw SQLite-query's genereert Floor DAO-klassen uit geannoteerde Dart-modellen. Volgens Pub.dev, 2024 wordt Floor gebruikt in meer dan 3500 Flutter-projecten en behoort het tot de top drie van populairste ORM-oplossingen voor lokale gegevensopslag, naast drift en hive.
Belangrijkste punten
Floor — is een ORM-bibliotheek voor Flutter en Dart, gebouwd op basis van SQLite. Het gebruikt annotaties om entiteiten (Entity), Data Access Object (DAO) en database (Database) te beschrijven. Codegeneratie gebeurt via build_runner en floor_generator — de compiler maakt DAO-implementaties en de beherende databaseklasse. In tegenstelling tot raw sqflite elimineert Floor volledig de noodzaak om handmatig ResultSet naar Dart-objecten te converteren, door automatisch kolommen naar Entity-velden te mappen via typereflectie.
Floor volgt het Repository + DAO-patroon, bekend bij Android-ontwikkelaars uit Room. Elke tabel wordt vertegenwoordigd door een Dart-klasse met de annotatie @Entity, SQL-query's worden gegroepeerd in interfaces met de annotatie @dao, en de database wordt samengesteld in een abstracte klasse met @Database. Deze aanpak scheidt het datamodel strikt van de querylogica.
Volgens Flutter Pulse (2023) wordt Floor gekozen in 28% van de Flutter-projecten die een lokale database vereisen. De belangrijkste redenen voor de keuze — bekendheid met SQL (geen nieuwe querytaal leren) en controle van query's tijdens compilatie. Bovendien genereert Floor leesbare code die gemakkelijk te debuggen is in tegenstelling tot meer abstracte ORM's met aangepaste DSL, wat de drempel voor nieuwe ontwikkelaars in het team verlaagt.
Floor bestaat uit drie lagen: Entity (tabelmodel), DAO (query-interface) en Database (ingangspunt). De generator maakt implementaties _$_Entity voor veldmapping en _$_Dao voor SQL-uitvoering. Bij wijziging van Entity of DAO is het voldoende om build_runner opnieuw te starten — de code wordt automatisch bijgewerkt. Voor migratie tussen schemaversies gebruikt Floor sequentiële versienummers, wat gegevensintegriteit garandeert bij het bijwerken van de app op gebruikersapparaten.
Floor gebruikt SQLite via het pakket sqflite voor platformbuilds en sqlite3 voor desktop en web. Bij het starten van de app maakt of opent Floor het SQLite-bestand, past migraties toe en bereidt DAO-methoden voor op het uitvoeren van query's. Alle bewerkingen worden asynchroon uitgevoerd via Future en Stream.
Codegeneratie in Floor werkt volgens het volgende principe: de parser leest annotaties uit de broncode, maakt een AST (Abstract Syntax Tree) van modellen en query's, en genereert vervolgens Dart-bestanden met het voorvoegsel _$. De gegenereerde code bevat mappers voor ResultSet → Entity en omgekeerd.
Floor werkt met SQLite in één isolaat. Alle query's worden asynchroon uitgevoerd, maar gelijktijdige schrijfbewerkingen worden geblokkeerd op SQLite-niveau. Voor transacties wordt de annotatie @transaction gebruikt, die de atomiciteit van een groep query's en terugdraaien bij fouten garandeert.
Zowel Floor als Drift — zijn ORM's bovenop SQLite, maar ze verschillen in filosofie. Floor staat dichter bij Room uit Android, Drift — is reactiever met ingebouwde Stream API en querycompilatie via SQL-bestanden. De keuze tussen hen hangt af van de ervaring van het team en de vereiste reactiviteit.
| Kenmerk | Floor | Drift |
|---|---|---|
| Querytype | SQL-strings in @Query | Dart-methoden + sql-bestanden |
| Codegeneratie | floor_generator (build_runner) | drift_dev (build_runner) |
| Reactiviteit | Stream uit DAO | Ingebouwde Stream API + auto-updating |
| Complexiteit | Laag (bekende SQL) | Middel (eigen DSL) |
| Migraties | Handmatige SQL-scripts | Automatisch + handmatig |
| Compatibiliteit | Android, iOS, macOS | Android, iOS, Web, macOS, Linux |
Floor — de keuze voor teams die al bekend zijn met SQL en Android Room. Als ontwikkelaars gewend zijn SQL-query's handmatig te schrijven en een minimale laag bovenop SQLite willen — biedt Floor typering zonder een nieuwe DSL te leren. Het is ook gemakkelijker te debuggen omdat de gegenereerde code leesbaar en voorspelbaar is.
Drift biedt krachtigere reactiviteit en ondersteunt meer platforms. Als de app actief Stream gebruikt voor UI-updates, complexe query's met JOIN en subquery's vereist, of voor web wordt gebouwd — heeft Drift de voorkeur. De instapdrempel is echter hoger vanwege de noodzaak om de eigen DSL te leren.
Floor is gebouwd rond annotaties. Hieronder staat een volledig voorbeeld van Entity, DAO en Database voor een takenlijst-app. Na het uitvoeren van build_runner zijn de gegenereerde klassen klaar voor gebruik.
De klasse TaskEntity met de annotatie @Entity wordt naar de tabel task gemapt. Het veld met @primaryKey wordt de primaire sleutel. De interface TaskDao bevat methoden voor bewerkingen op de tabel — elke methode is geannoteerd met @Query, @Insert, @Update of @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);
}
De abstracte klasse met de annotatie @Database verbindt Entity en DAO. De methode databaseBuilder maakt een database-instantie. Na het aanroepen van build is de database klaar: Floor opent het SQLite-bestand, past migraties toe en retourneert DAO voor gebruik.
@Database(version: 1, entities: [TaskEntity])
abstract class AppDatabase extends FloorDatabase {
TaskDao get taskDao;
}
// Gebruik
final database = await $FloorAppDatabase.databaseBuilder('app.db').build();
final taskDao = database.taskDao;
final tasks = await taskDao.getAllTasks();
Floor ondersteunt het retourneren van Stream uit DAO-methoden. Bij elke wijziging in de tabel zendt Stream een nieuwe lijst uit. Dit integreert met StreamBuilder in Flutter — de UI wordt automatisch bijgewerkt bij het toevoegen, wijzigen of verwijderen van records.
@Query('SELECT * FROM TaskEntity ORDER BY priority DESC')
Stream<List<TaskEntity>> watchAllTasks();
// In Flutter-widget
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 ondersteunt versiebeheer van de database via de parameter version in de annotatie @Database. Bij wijziging van Entity (toevoegen of verwijderen van velden) moet u de versie verhogen en een migratie toevoegen. Een migratie is een Dart-functie die een transactie ontvangt en SQL-query's ALTER TABLE uitvoert.
Stel dat we in versie 2 het veld dueDate aan TaskEntity hebben toegevoegd. De migratie wordt uitgevoerd met de SQL-query ALTER TABLE. Als er geen migratie is opgegeven, roept Floor MigrationStrategy aan, waar een fallback kan worden ingesteld (bijvoorbeeld het opnieuw aanmaken van de tabel met gegevensverlies).
Floor biedt geen ingebouwd mock-framework, maar de database kan eenvoudig worden vervangen in tests. Maak inMemoryDatabaseBuilder — het maakt een SQLite-database in het geheugen, qua schema identiek aan de productie. Na elke test wist u de gegevens via deleteDatabase voor isolatie van testscenario's.
Floor ondersteunt transacties via de annotatie @transaction op de DAO-methode. Binnen een transactie worden meerdere query's sequentieel uitgevoerd met terugdraaigarantie bij fouten. Batch-invoeging via @Insert met de parameter List<T> optimaliseert het invoegen van meerdere records in één aanroep — dit is meerdere keren sneller dan het afzonderlijk invoegen in een lus. Gebruik voor massale bewerkingen batch-invoeging van 100–200 records: dit is de optimale balans tussen uitvoeringssnelheid en RAM-verbruik op mobiele apparaten met beperkte middelen.
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();
Veelgestelde vragen
sqflite vereist het handmatig schrijven van SQL-query's en het mappen van ResultSet naar objecten. Floor genereert deze code automatisch: u beschrijft Entity en DAO, en getypeerde methoden retourneren kant-en-klare Dart-objecten. Floor controleert ook SQL-query's tijdens compilatie via annotaties.
Floor heeft geen ingebouwde annotaties voor relaties (ForeignKey, @Relation), zoals Room. Relaties worden geïmplementeerd via handmatige SQL JOIN-query's in @Query. Voor complexe relationele schema's kunt u beter Drift overwegen met zijn ingebouwde ondersteuning voor relaties.
Floor maakt het mogelijk om de callback callback in te schakelen bij het maken van DatabaseBuilder — hieraan wordt een instantie van sqflite.Database doorgegeven waar een logger aan kan worden gekoppeld. Gebruik alternatief floor_doctor voor visualisatie van het schema en gegevens in de ontwikkelmodus.
Floor gebruikt sqflite, dat niet werkt in een webomgeving. Voor web is een aparte build met sqlite3 via WASM nodig. In de huidige versie ondersteunt Floor officieel Android, iOS en macOS. Gebruik voor web Drift met de sqlite3-adapter.
Floor heeft geen ingebouwde caching — elke query wordt uitgevoerd naar SQLite. Gebruik voor het cachen van herhaalde query's een Repository-laag met in-memory cache (bijvoorbeeld dart_cache). Floor genereert alleen code voor het werken met SQLite, zonder er extra lagen bovenop toe te voegen.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook