Floor — ce este, ORM peste SQLite în Flutter

Autor: IT Sectr Publicat: 2026-03-13 Timp de citire: 9 min

Floor — ORM (Object-Relational Mapping) pentru Flutter, care oferă un strat tipizat peste SQLite. Spre deosebire de interogările SQLite brute, Floor generează clase DAO din modele Dart adnotate. Conform datelor Pub.dev, 2024, Floor este utilizat în peste 3500 de proiecte Flutter și se află în top trei cele mai populare soluții ORM pentru stocarea locală a datelor, alături de drift și hive.

Principalele puncte

  • Floor — ORM peste SQLite cu generare de cod DAO și Entity prin adnotări
  • Siguranța tipurilor — interogările sunt verificate la compilare, eliminând erorile SQL de runtime
  • Modelul DAO — Data Access Object încapsulează interogările SQL în metode Dart
  • Migrări — suport încorporat pentru versionarea schemei SQLite
  • Reactitivitate — interogări Flow prin Stream pentru actualizarea automată a UI

Ce este Floor?

Floor — este o bibliotecă ORM pentru Flutter și Dart, construită pe baza SQLite. Utilizează adnotări pentru a descrie entități (Entity), Data Access Object (DAO) și baza de date (Database). Generarea codului se realizează prin build_runner și floor_generator — compilatorul creează implementări DAO și clasa de gestionare a bazei de date. Spre deosebire de sqflite brut, Floor elimină complet necesitatea conversiei manuale a ResultSet în obiecte Dart, mapând automat coloanele pe câmpurile Entity prin reflexia tipurilor.

Floor urmează modelul Repository + DAO, cunoscut dezvoltatorilor Android din Room. Fiecare tabel este reprezentat de o clasă Dart cu adnotarea @Entity, interogările SQL sunt grupate în interfețe cu adnotarea @dao, iar baza de date este compusă într-o clasă abstractă cu @Database. Această abordare separă strict modelul de date și logica interogărilor.

Conform Flutter Pulse (2023), Floor este ales în 28% din proiectele Flutter care necesită o bază de date locală. Principalele motive de alegere — cunoașterea SQL (nu este nevoie să înveți un nou limbaj de interogare) și verificarea interogărilor la compilare. În plus, Floor generează cod citibil, care este ușor de depanat spre deosebire de ORM-uri mai abstracte cu DSL personalizat, ceea ce reduce pragul de intrare pentru noii dezvoltatori din echipă.

Arhitectura Floor

Floor constă din trei straturi: Entity (modelul tabelului), DAO (interfața interogărilor) și Database (punctul de intrare). Generatorul creează implementări _$_Entity pentru maparea câmpurilor și _$_Dao pentru executarea SQL. La modificarea Entity sau DAO este suficient să reporniți build_runner — codul se va actualiza automat. Pentru migrarea între versiunile schemei, Floor utilizează numere de versiune secvențiale, garantând integritatea datelor la actualizarea aplicației pe dispozitivele utilizatorilor.

Cum funcționează Floor în Flutter?

Floor utilizează SQLite prin pachetul sqflite pentru compilări platformă și sqlite3 pentru desktop și web. La pornirea aplicației, Floor creează sau deschide fișierul SQLite, aplică migrările și pregătește metodele DAO pentru executarea interogărilor. Toate operațiile se execută în mod asincron prin Future și Stream.

Generarea codului în Floor funcționează după următorul principiu: parserul citește adnotările din codurile sursă, creează AST (Abstract Syntax Tree) al modelelor și interogărilor, apoi generează fișiere Dart cu prefixul _$. Codul generat include mapări ResultSet → Entity și invers.

Siguranța firelor

Floor lucrează cu SQLite într-un singur izolat. Toate interogările se execută asincron, dar scrierile concurente sunt blocate la nivelul SQLite. Pentru tranzacții se utilizează adnotarea @transaction, care garantează atomicitatea grupului de interogări și revenirea în caz de eroare.

Floor vs Drift: compararea ORM pentru Flutter

Atât Floor, cât și Drift — sunt ORM peste SQLite, dar diferă prin filozofie. Floor este mai aproape de Room din Android, Drift — mai reactiv cu Stream API încorporat și compilarea interogărilor prin fișiere SQL. Alegerea dintre ele depinde de experiența echipei și reactivitatea necesară.

CaracteristicăFloorDrift
Tip interogăriStringuri SQL în @QueryMetode Dart + fișiere sql
Generare codfloor_generator (build_runner)drift_dev (build_runner)
ReactitivitateStream din DAOStream API încorporat + auto-updating
ComplexitateScăzută (SQL familiar)Medie (DSL propriu)
MigrăriScripturi SQL manualeAutomatice + manuale
CompatibilitateAndroid, iOS, macOSAndroid, iOS, Web, macOS, Linux

Când să alegem Floor

Floor — alegerea echipelor care cunosc deja SQL și Android Room. Dacă dezvoltatorii sunt obișnuiți să scrie interogări SQL manual și doresc un strat minim peste SQLite — Floor oferă tipizare fără a învăța un nou DSL. Este, de asemenea, mai ușor de depanat, deoarece codul generat este citibil și previzibil.

Când este mai bun Drift

Drift oferă o reactivitate mai puternică și suportă mai multe platforme. Dacă aplicația utilizează activ Stream pentru actualizarea UI, necesită interogări complexe cu JOIN și subinterogări sau este construită pentru web — Drift este preferabil. Totuși, pragul său de intrare este mai ridicat din cauza necesității de a învăța propriul DSL.

Exemple de cod cu Floor

Floor este construit în jurul adnotărilor. Mai jos este un exemplu complet de Entity, DAO și Database pentru o aplicație listă de sarcini. După rularea build_runner, clasele generate sunt gata de utilizare.

Definirea Entity și DAO

Clasa TaskEntity cu adnotarea @Entity se mapează pe tabelul task. Câmpul cu @primaryKey devine cheia primară. Interfața TaskDao conține metode pentru operații cu tabelul — fiecare metodă este adnotată cu @Query, @Insert, @Update sau @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);
}

Inițializarea bazei de date

Clasa abstractă cu adnotarea @Database leagă Entity și DAO. Metoda databaseBuilder creează o instanță a bazei de date. După apelarea build, baza este gata: Floor deschide fișierul SQLite, aplică migrările și returnează DAO pentru lucru.

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

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

Interogări reactive prin Stream

Floor suportă returnarea Stream din metodele DAO. La orice modificare în tabel, Stream emite o nouă listă. Acest lucru se integrează cu StreamBuilder în Flutter — UI se actualizează automat la adăugarea, modificarea sau ștergerea înregistrărilor.

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

// În widgetul 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]),
        );
    },
)

Migrări și versionare în Floor

Floor suportă versionarea bazei de date prin parametrul version în adnotarea @Database. La modificarea Entity (adăugarea sau eliminarea câmpurilor) trebuie să creșteți versiunea și să adăugați o migrare. Migrarea este o funcție Dart care primește o tranzacție și execută interogări SQL ALTER TABLE.

Exemplu de migrare

Să presupunem că în versiunea 2 am adăugat câmpul dueDate în TaskEntity. Migrarea se execută prin interogarea SQL ALTER TABLE. Dacă migrarea nu este specificată, Floor apelează MigrationStrategy, unde se poate seta un fallback (de exemplu, recrearea tabelului cu pierderea datelor).

Testarea interogărilor Floor

Floor nu oferă un framework de mock încorporat, dar baza de date poate fi ușor înlocuită în teste. Creați inMemoryDatabaseBuilder — creează o bază SQLite în memorie, identică ca schemă cu cea de producție. După fiecare test, ștergeți datele prin deleteDatabase pentru izolarea scenariilor de test.

Tranzacții și operații batch în Floor

Floor suportă tranzacții prin adnotarea @transaction pe metoda DAO. În interiorul tranzacției, mai multe interogări se execută secvențial cu garanția revenirii la eroare. Inserarea batch prin @Insert cu parametrul List<T> optimizează inserarea mai multor înregistrări într-un singur apel — este de câteva ori mai rapidă decât inserarea individuală în buclă. Pentru operații masive, utilizați inserarea batch cu 100–200 de înregistrări: acesta este echilibrul optim între viteza de executare și consumul de RAM pe dispozitivele mobile cu resurse limitate.

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

Întrebări frecvente

Cu ce se deosebește Floor de sqflite brut?

sqflite necesită scrierea manuală a interogărilor SQL și maparea ResultSet în obiecte. Floor generează acest cod automat: descrieți Entity și DAO, iar metodele tipizate returnează obiecte Dart gata preparate. Floor verifică, de asemenea, interogările SQL la compilare prin adnotări.

Suportă Floor relații între tabele?

Floor nu are adnotări încorporate pentru relații (ForeignKey, @Relation), ca Room. Relațiile se implementează prin interogări manuale SQL JOIN în @Query. Pentru scheme relaționale complexe, este mai bine să luați în considerare Drift cu suportul său încorporat pentru relații.

Cum se depanează interogările SQL Floor?

Floor permite activarea callback-ului callback la crearea DatabaseBuilder — în el se transmite instanța sqflite.Database de care se poate atașa un logger. Alternativ, utilizați floor_doctor pentru vizualizarea schemei și datelor în modul de dezvoltare.

Se poate utiliza Floor pentru compilarea web?

Floor utilizează sqflite, care nu funcționează în mediul web. Pentru web este necesară o compilare separată cu sqlite3 prin WASM. În versiunea actuală, Floor suportă oficial Android, iOS și macOS. Pentru web, utilizați Drift cu adaptorul sqlite3.

Cum funcționează cache-ul interogărilor în Floor?

Floor nu are cache încorporat — fiecare interogare se execută către SQLite. Pentru cache-ul interogărilor repetitive, utilizați stratul Repository cu cache în memorie (de exemplu, dart_cache). Floor doar generează cod pentru lucrul cu SQLite, fără a adăuga straturi suplimentare.

Concluzii

  • Floor — ORM peste SQLite cu generare de cod Entity, DAO și Database prin adnotări
  • Siguranța tipurilor — interogările SQL sunt verificate la compilare prin adnotarea @Query
  • Modelul DAO — interogările SQL încapsulate în metode Dart, separând modelul de logică
  • Migrări — versionarea schemei prin Migration cu ALTER TABLE manual
  • Reactitivitate — Stream din DAO pentru actualizarea automată a UI la modificări
  • Limitări — fără relații încorporate, nu suportă compilarea web
  • Recomandare — alegeți Floor pentru proiecte Flutter unde echipa cunoaște SQL și abordarea Room

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și