Floor — vad är det, ORM ovanpå SQLite i Flutter

Författare: IT Sectr Publicerad: 2026-03-13 Lästid: 9 min

Floor — ORM (Object-Relational Mapping) för Flutter som tillhandahåller ett typat lager ovanpå SQLite. Till skillnad från råa SQLite-frågor genererar Floor DAO-klasser från annoterade Dart-modeller. Enligt Pub.dev, 2024 används Floor i över 3500 Flutter-projekt och är bland de tre mest populära ORM-lösningarna för lokal datalagring tillsammans med drift och hive.

Huvudpunkter

  • Floor — ORM ovanpå SQLite med kodgenerering av DAO och Entity via annoteringar
  • Typsäkerhet — frågor kontrolleras vid kompilering, vilket eliminerar runtime SQL-fel
  • DAO-mönster — Data Access Object inkapslar SQL-frågor i Dart-metoder
  • Migreringar — inbyggt stöd för versionshantering av SQLite-schema
  • Reaktivitet — Flow-frågor via Stream för automatisk UI-uppdatering

Vad är Floor?

Floor — är ett ORM-bibliotek för Flutter och Dart, byggt ovanpå SQLite. Det använder annoteringar för att beskriva entiteter (Entity), Data Access Object (DAO) och databas (Database). Kodgenerering utförs via build_runner och floor_generator — kompilatorn skapar DAO-implementationer och den hanterande databasklassen. Till skillnad från rå sqflite eliminerar Floor helt behovet av manuell konvertering av ResultSet till Dart-objekt, genom att automatiskt mappa kolumner till Entity-fält via typreflektion.

Floor följer mönstret Repository + DAO, känt för Android-utvecklare från Room. Varje tabell representeras av en Dart-klass med annoteringen @Entity, SQL-frågor grupperas i gränssnitt med annoteringen @dao, och databasen sammanställs i en abstrakt klass med @Database. Detta tillvägagångssätt separerar strikt datamodellen från frågelogiken.

Enligt Flutter Pulse (2023) väljs Floor i 28% av Flutter-projekt som kräver en lokal databas. De främsta anledningarna till valet — kännedom om SQL (ingen ny frågespråk att lära) och kontroll av frågor vid kompilering. Dessutom genererar Floor läsbar kod som är lätt att felsöka till skillnad från mer abstrakta ORM med anpassad DSL, vilket sänker tröskeln för nya utvecklare i teamet.

Floor-arkitektur

Floor består av tre lager: Entity (tabellmodell), DAO (frågegränssnitt) och Database (ingångspunkt). Generatorn skapar implementationer _$_Entity för fältmappning och _$_Dao för SQL-exekvering. När Entity eller DAO ändras räcker det att starta om build_runner — koden uppdateras automatiskt. För migrering mellan schemaversioner använder Floor sekventiella versionsnummer, vilket garanterar dataintegritet vid uppdatering av appen på användarnas enheter.

Hur fungerar Floor i Flutter?

Floor använder SQLite via paketet sqflite för plattformsbyggen och sqlite3 för desktop och webb. När appen startar skapar eller öppnar Floor SQLite-filen, tillämpar migreringar och förbereder DAO-metoder för att utföra frågor. Alla operationer utförs asynkront via Future och Stream.

Kodgenerering i Floor fungerar enligt följande princip: parsern läser annoteringar från källkoden, skapar ett AST (Abstract Syntax Tree) av modeller och frågor, genererar sedan Dart-filer med prefixet _$. Den genererade koden inkluderar mappare för ResultSet → Entity och vice versa.

Trådsäkerhet

Floor arbetar med SQLite i en isolat. Alla frågor utförs asynkront, men samtidiga skrivningar blockeras på SQLite-nivå. För transaktioner används annoteringen @transaction, som garanterar atomicitet för en grupp frågor och återställning vid fel.

Floor vs Drift: jämförelse av ORM för Flutter

Både Floor och Drift — är ORM ovanpå SQLite, men de skiljer sig i filosofi. Floor är närmare Room från Android, Drift — är mer reaktiv med inbyggt Stream API och kompilering av frågor via SQL-filer. Valet mellan dem beror på teamets erfarenhet och önskad reaktivitet.

EgenskapFloorDrift
FrågetypSQL-strängar i @QueryDart-metoder + sql-filer
Kodgenereringfloor_generator (build_runner)drift_dev (build_runner)
ReaktivitetStream från DAOInbyggt Stream API + auto-updating
KomplexitetLåg (bekant SQL)Medel (egen DSL)
MigreringarManuella SQL-skriptAutomatiska + manuella
KompatibilitetAndroid, iOS, macOSAndroid, iOS, Web, macOS, Linux

När välja Floor

Floor — valet för team som redan känner till SQL och Android Room. Om utvecklare är vana att skriva SQL-frågor manuellt och vill ha ett minimalt lager ovanpå SQLite — ger Floor typning utan att lära sig en ny DSL. Det är också lättare att felsöka eftersom den genererade koden är läsbar och förutsägbar.

När Drift är bättre

Drift ger starkare reaktivitet och stöder fler plattformar. Om appen aktivt använder Stream för UI-uppdatering, kräver komplexa frågor med JOIN och underfrågor, eller byggs för webb — är Drift att föredra. Dess tröskel är dock högre på grund av behovet att lära sig sin egen DSL.

Kodexempel med Floor

Floor är byggt kring annoteringar. Nedan finns ett komplett exempel på Entity, DAO och Database för en att-göra-lista-app. Efter att ha kört build_runner är de genererade klasserna redo att användas.

Definition av Entity och DAO

Klassen TaskEntity med annoteringen @Entity mappas till tabellen task. Fältet med @primaryKey blir primärnyckel. Gränssnittet TaskDao innehåller metoder för tabelloperationer — varje metod är annoterad med @Query, @Insert, @Update eller @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);
}

Initiering av databas

Den abstrakta klassen med annoteringen @Database kopplar samman Entity och DAO. Metoden databaseBuilder skapar en databasinstans. Efter anrop av build är databasen redo: Floor öppnar SQLite-filen, tillämpar migreringar och returnerar DAO för arbete.

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

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

Reaktiva frågor via Stream

Floor stöder returnering av Stream från DAO-metoder. Vid varje ändring i tabellen sänder Stream ut en ny lista. Detta integreras med StreamBuilder i Flutter — UI uppdateras automatiskt vid tillägg, ändring eller borttagning av poster.

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

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

Migreringar och versionshantering i Floor

Floor stöder versionshantering av databasen via parametern version i annoteringen @Database. När Entity ändras (lägga till eller ta bort fält) måste du öka versionen och lägga till en migrering. Migreringen är en Dart-funktion som tar emot en transaktion och utför SQL-frågor ALTER TABLE.

Migreringsexempel

Anta att vi i version 2 lade till fältet dueDate i TaskEntity. Migreringen utförs med SQL-frågan ALTER TABLE. Om migrering inte anges anropar Floor MigrationStrategy, där en fallback kan ställas in (till exempel återskapande av tabell med dataförlust).

Testning av Floor-frågor

Floor tillhandahåller inget inbyggt mock-ramverk, men databasen kan enkelt ersättas i tester. Skapa inMemoryDatabaseBuilder — det skapar en SQLite-databas i minnet, identisk i schema med produktion. Efter varje test rensar du data via deleteDatabase för isolering av testscenarier.

Transaktioner och batch-operationer i Floor

Floor stöder transaktioner via annoteringen @transaction på DAO-metoden. Inuti en transaktion utförs flera frågor sekventiellt med garanti för återställning vid fel. Batch-insättning via @Insert med parametern List<T> optimerar insättning av flera poster i ett anrop — detta är flera gånger snabbare än att sätta in en och en i en loop. För massoperationer, använd batch-insättning med 100–200 poster: detta är den optimala balansen mellan exekveringshastighet och RAM-förbrukning på mobila enheter med begränsade resurser.

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();

Vanliga frågor

Vad skiljer Floor från rå sqflite?

sqflite kräver manuell skrivning av SQL-frågor och mappning av ResultSet till objekt. Floor genererar denna kod automatiskt: du beskriver Entity och DAO, och typade metoder returnerar färdiga Dart-objekt. Floor kontrollerar också SQL-frågor vid kompilering via annoteringar.

Stöder Floor relationer mellan tabeller?

Floor har inga inbyggda annoteringar för relationer (ForeignKey, @Relation) som Room. Relationer implementeras via manuella SQL JOIN-frågor i @Query. För komplexa relationsscheman är det bättre att överväga Drift med dess inbyggda stöd för relationer.

Hur felsöker man Floor SQL-frågor?

Floor gör det möjligt att aktivera callback callback när DatabaseBuilder skapas — en instans av sqflite.Database skickas till den, på vilken en logger kan kopplas. Alternativt, använd floor_doctor för visualisering av schema och data i utvecklingsläge.

Kan Floor användas för webbbyggen?

Floor använder sqflite som inte fungerar i webbmiljö. För webb krävs ett separat bygge med sqlite3 via WASM. I nuvarande version stöder Floor officiellt Android, iOS och macOS. För webb, använd Drift med sqlite3-adapter.

Hur fungerar frågecachning i Floor?

Floor har ingen inbyggd cachning — varje fråga utförs mot SQLite. För cachning av återkommande frågor, använd ett Repository-lager med cache i minnet (till exempel dart_cache). Floor genererar bara kod för att arbeta med SQLite, utan att lägga till lager ovanpå det.

Sammanfattning

  • Floor — ORM ovanpå SQLite med kodgenerering av Entity, DAO och Database via annoteringar
  • Typsäkerhet — SQL-frågor kontrolleras vid kompilering via annoteringen @Query
  • DAO-mönster — SQL-frågor inkapslade i Dart-metoder, som separerar modell och logik
  • Migreringar — schemaversionshantering via Migration med manuell ALTER TABLE
  • Reaktivitet — Stream från DAO för automatisk UI-uppdatering vid ändringar
  • Begränsningar — inga inbyggda relationer, stöder inte webbbyggen
  • Rekommendation — välj Floor för Flutter-projekt där teamet känner till SQL och Room-metoden

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också