Floor — ORM (Object-Relational Mapping) para sa Flutter na nagbibigay ng may-type na layer sa ibabaw ng SQLite. Hindi tulad ng raw SQLite query, ang Floor ay bumubuo ng DAO class mula sa mga anotadong Dart model. Ayon sa datos ng Pub.dev, 2024, ang Floor ay ginagamit sa mahigit 3500 Flutter project at kabilang sa tatlong pinakasikat na ORM solution para sa lokal na pag-imbak ng datos kasama ng drift at hive.
Mga Pangunahing Punto
Floor — ay isang ORM library para sa Flutter at Dart na binuo sa ibabaw ng SQLite. Gumagamit ito ng mga anotasyon para ilarawan ang mga entity (Entity), Data Access Object (DAO) at database (Database). Ang code generation ay ginagawa sa pamamagitan ng build_runner at floor_generator — lumilikha ang compiler ng mga DAO implementation at ang managing database class. Hindi tulad ng raw sqflite, ganap na inaalis ng Floor ang pangangailangan para sa manu-manong conversion ng ResultSet sa Dart object, awtomatikong nagma-map ng mga column sa Entity field sa pamamagitan ng type reflection.
Ang Floor ay sumusunod sa pattern ng Repository + DAO na pamilyar sa mga Android developer mula sa Room. Ang bawat table ay kinakatawan ng isang Dart class na may anotasyong @Entity, ang mga SQL query ay pinagsama-sama sa mga interface na may anotasyong @dao, at ang database ay binuo sa isang abstract class na may @Database. Ang pamamaraang ito ay mahigpit na naghihiwalay ng data model at query logic.
Ayon sa Flutter Pulse (2023), ang Floor ay pinipili sa 28% ng Flutter project na nangangailangan ng lokal na database. Ang mga pangunahing dahilan ng pagpili — kaalaman sa SQL (hindi na kailangan matuto ng bagong query language) at pagsusuri ng query sa compilation. Bukod pa rito, ang Floor ay bumubuo ng nababasang code na madaling i-debug hindi tulad ng mas abstract na ORM na may custom na DSL, na nagpapababa ng threshold para sa mga bagong developer sa team.
Floor ay binubuo ng tatlong layer: Entity (model ng table), DAO (interface ng query) at Database (entry point). Lumilikha ang generator ng mga implementation na _$_Entity para sa pagma-map ng field at _$_Dao para sa pag-execute ng SQL. Kapag binago ang Entity o DAO, sapat na ang i-restart ang build_runner — awtomatikong maa-update ang code. Para sa migrasyon sa pagitan ng mga bersyon ng schema, gumagamit ang Floor ng sequential version number na naggarantiya ng integridad ng datos sa pag-update ng app sa mga device ng user.
Floor ay gumagamit ng SQLite sa pamamagitan ng package na sqflite para sa platform build at sqlite3 para sa desktop at web. Sa pagsisimula ng app, ang Floor ay lumilikha o nagbubukas ng SQLite file, nag-a-apply ng migrasyon at naghahanda ng DAO method para sa pag-execute ng query. Lahat ng operasyon ay ginagawa sa asynchronous mode sa pamamagitan ng Future at Stream.
Ang code generation sa Floor ay gumagana ayon sa sumusunod na prinsipyo: binabasa ng parser ang mga anotasyon mula sa source code, lumilikha ng AST (Abstract Syntax Tree) ng mga modelo at query, pagkatapos ay bumubuo ng Dart file na may prefix na _$. Ang nabuong code ay may kasamang mapper para sa ResultSet → Entity at vice versa.
Floor ay gumagana sa SQLite sa isang isolate. Lahat ng query ay ginagawa nang asynchronous, ngunit ang concurrent na pagsulat ay na-block sa antas ng SQLite. Para sa transaksyon, ginagamit ang anotasyong @transaction na naggarantiya ng atomicity ng group ng query at rollback sa error.
Parehong Floor at Drift — ay ORM sa ibabaw ng SQLite, ngunit nagkakaiba sila sa pilosopiya. Ang Floor ay mas malapit sa Room mula sa Android, ang Drift — ay mas reaktibo na may built-in na Stream API at compilation ng query sa pamamagitan ng SQL file. Ang pagpili sa pagitan nila ay depende sa karanasan ng team at kinakailangang reaktibidad.
| Katangian | Floor | Drift |
|---|---|---|
| Uri ng query | SQL string sa @Query | Dart method + sql file |
| Code generation | floor_generator (build_runner) | drift_dev (build_runner) |
| Reaktibidad | Stream mula sa DAO | Built-in Stream API + auto-updating |
| Kompleksidad | Mababa (pamilyar na SQL) | Katamtaman (sariling DSL) |
| Migrasyon | Manu-manong SQL script | Awtomatiko + manu-mano |
| Kompatibilidad | Android, iOS, macOS | Android, iOS, Web, macOS, Linux |
Floor — pagpili ng mga team na pamilyar na sa SQL at Android Room. Kung ang mga developer ay sanay na magsulat ng SQL query nang manu-mano at gusto ng minimal na wrapper sa ibabaw ng SQLite — nagbibigay ang Floor ng typing nang hindi natututo ng bagong DSL. Ito rin ay mas madaling i-debug dahil ang nabuong code ay nababasa at predictable.
Drift ay nagbibigay ng mas malakas na reaktibidad at sumusuporta sa mas maraming platform. Kung ang app ay aktibong gumagamit ng Stream para sa pag-update ng UI, nangangailangan ng kumplikadong query na may JOIN at subquery, o binuo para sa web — mas preferred ang Drift. Gayunpaman, mas mataas ang threshold nito dahil sa pangangailangang matutunan ang sarili nitong DSL.
Floor ay binuo sa paligid ng mga anotasyon. Sa ibaba ay isang kumpletong halimbawa ng Entity, DAO at Database para sa isang task list app. Pagkatapos patakbuhin ang build_runner, ang mga nabuong class ay handa nang gamitin.
Ang class na TaskEntity na may anotasyong @Entity ay nagma-map sa table na task. Ang field na may @primaryKey ay nagiging primary key. Ang interface na TaskDao ay naglalaman ng method para sa operasyon sa table — bawat method ay anotado ng @Query, @Insert, @Update o @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);
}
Ang abstract class na may anotasyong @Database ay nag-uugnay ng Entity at DAO. Ang method na databaseBuilder ay lumilikha ng instance ng database. Pagkatapos tawagin ang build, handa na ang database: binubuksan ng Floor ang SQLite file, nag-a-apply ng migrasyon at nagbabalik ng DAO para sa paggamit.
@Database(version: 1, entities: [TaskEntity])
abstract class AppDatabase extends FloorDatabase {
TaskDao get taskDao;
}
// Paggamit
final database = await $FloorAppDatabase.databaseBuilder('app.db').build();
final taskDao = database.taskDao;
final tasks = await taskDao.getAllTasks();
Floor ay sumusuporta sa pagbabalik ng Stream mula sa DAO method. Sa anumang pagbabago sa table, ang Stream ay naglalabas ng bagong listahan. Ito ay nag-i-integrate sa StreamBuilder sa Flutter — awtomatikong nag-a-update ang UI sa pagdagdag, pagbabago o pagtanggal ng record.
@Query('SELECT * FROM TaskEntity ORDER BY priority DESC')
Stream<List<TaskEntity>> watchAllTasks();
// Sa 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 ay sumusuporta sa versioning ng database sa pamamagitan ng parameter na version sa anotasyong @Database. Kapag binago ang Entity (pagdagdag o pagtanggal ng field), kailangan dagdagan ang version at magdagdag ng migrasyon. Ang migrasyon ay isang Dart function na tumatanggap ng transaksyon at nag-execute ng SQL query na ALTER TABLE.
Kunwari, sa version 2 ay nagdagdag kami ng field na dueDate sa TaskEntity. Ang migrasyon ay ginagawa sa pamamagitan ng SQL query na ALTER TABLE. Kung hindi tinukoy ang migrasyon, tinatawag ng Floor ang MigrationStrategy kung saan maaaring itakda ang fallback (halimbawa, muling paggawa ng table na may pagkawala ng datos).
Floor ay hindi nagbibigay ng built-in na mock framework, ngunit ang database ay madaling mapalitan sa mga test. Gumawa ng inMemoryDatabaseBuilder — lumilikha ito ng SQLite database sa memory, magkapareho ng schema sa production. Pagkatapos ng bawat test, linisin ang datos sa pamamagitan ng deleteDatabase para sa isolation ng test scenario.
Floor ay sumusuporta sa transaksyon sa pamamagitan ng anotasyong @transaction sa DAO method. Sa loob ng transaksyon, maraming query ang ginagawa nang sunud-sunod na may garantiya ng rollback sa error. Ang batch insertion sa pamamagitan ng @Insert na may parameter na List<T> ay nag-o-optimize ng pagpasok ng maraming record sa isang tawag — ito ay ilang beses na mas mabilis kaysa sa paisa-isang pagpasok sa loop. Para sa malawakang operasyon, gumamit ng batch insertion na 100–200 record: ito ang optimal na balanse sa pagitan ng bilis ng execution at konsumo ng RAM sa mga mobile device na may limitadong resources.
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();
Mga Madalas Itanong
sqflite ay nangangailangan ng manu-manong pagsulat ng SQL query at pagma-map ng ResultSet sa mga object. Awtomatikong binuo ng Floor ang code na ito: inilalarawan mo ang Entity at DAO, at ang mga naka-type na method ay nagbabalik ng handa nang Dart object. Sinusuri rin ng Floor ang SQL query sa compilation sa pamamagitan ng mga anotasyon.
Floor ay walang built-in na anotasyon para sa relasyon (ForeignKey, @Relation) tulad ng Room. Ang relasyon ay na-implement sa pamamagitan ng manu-manong SQL JOIN query sa @Query. Para sa kumplikadong relational schema, mas mainam na isaalang-alang ang Drift na may built-in na suporta para sa relasyon.
Floor ay nagbibigay-daan sa pag-activate ng callback na callback sa paggawa ng DatabaseBuilder — ang instance ng sqflite.Database ay ipinapasa dito kung saan maaaring ikabit ang logger. Bilang alternatibo, gamitin ang floor_doctor para sa visualization ng schema at datos sa dev mode.
Floor ay gumagamit ng sqflite na hindi gumagana sa web environment. Para sa web, kailangan ng hiwalay na build na may sqlite3 sa pamamagitan ng WASM. Sa kasalukuyang bersyon, opisyal na sinusuportahan ng Floor ang Android, iOS at macOS. Para sa web, gamitin ang Drift na may sqlite3 adapter.
Floor ay walang built-in na caching — bawat query ay ginagawa sa SQLite. Para sa caching ng paulit-ulit na query, gamitin ang Repository layer na may in-memory cache (halimbawa, dart_cache). Ang Floor ay bumubuo lamang ng code para sa paggawa gamit ang SQLite, nang hindi nagdadagdag ng mga layer sa ibabaw nito.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din