Floor — ORM (Object-Relational Mapping) для Flutter, що надає типізований прошарок поверх SQLite. На відміну від сирих SQLite-запитів, Floor генерує DAO-класи з анотованих Dart-моделей. За даними Pub.dev, 2024, Floor використовується більш ніж у 3500 Flutter-проектах і входить до трійки найпопулярніших ORM-рішень для локального зберігання даних поряд з drift та hive.
Головне
Floor — це ORM-бібліотека для Flutter та Dart, побудована на основі SQLite. Вона використовує анотації для опису сутностей (Entity), Data Access Objects (DAO) та бази даних (Database). Генерація коду виконується через build_runner та floor_generator — компілятор створює реалізації DAO та керуючий клас бази даних. На відміну від сирого sqflite, Floor повністю усуває необхідність ручного перетворення ResultSet у Dart-об'єкти, автоматично маплячи стовпці на поля Entity через відображення типів.
Floor слідує шаблону Repository + DAO, знайомому розробникам Android по Room. Кожна таблиця представлена Dart-класом з анотацією @Entity, SQL-запити групуються в інтерфейсах з анотацією @dao, а база даних збирається в абстрактному класі з @Database. Такий підхід строго розділяє модель даних і логіку запитів.
За даними Flutter Pulse (2023), Floor обирають у 28% Flutter-проектів, де потрібна локальна БД. Основні причини вибору — знайомство з SQL (не потрібно вчити нову мову запитів) та перевірка запитів на етапі компіляції. Крім того, Floor генерує читабельний код, який легко налагоджувати на відміну від більш абстрактних ORM з кастомним DSL, що знижує поріг входу для нових розробників у команді.
Floor складається з трьох шарів: Entity (модель таблиці), DAO (інтерфейс запитів) та Database (точка входу). Генератор створює реалізації _$_Entity для маппінгу полів та _$_Dao для виконання SQL. При зміні Entity або DAO достатньо перезапустити build_runner — код оновиться автоматично. Для міграції між версіями схеми Floor використовує послідовні номери версій, що гарантує цілісність даних при оновленні додатку на пристроях користувачів.
Floor використовує SQLite через пакет sqflite для платформених збірок та sqlite3 для десктопу та веб. При запуску додатку Floor створює або відкриває SQLite-файл, застосовує міграції та підготовлює DAO-методи для виконання запитів. Всі операції виконуються в асинхронному режимі через Future та Stream.
Генерація коду в Floor працює за наступним принципом: парсер зчитує анотації з вихідників, створює AST (Abstract Syntax Tree) моделей та запитів, після чого генерує Dart-файли з префіксом _$. Згенерований код включає мапери ResultSet → Entity та назад.
Floor працює з SQLite в одному ізоляті. Всі запити виконуються асинхронно, але конкурентні записи блокуються на рівні SQLite. Для транзакцій використовується анотація @transaction, яка гарантує атомарність групи запитів та відкат при помилці.
І Floor, і Drift — ORM поверх SQLite, але вони різняться за філософією. Floor ближче до Room з Android, Drift — більш реактивний з вбудованим Stream API та компіляцією запитів через SQL-файли. Вибір між ними залежить від досвіду команди та необхідної реактивності.
| Характеристика | Floor | Drift |
|---|---|---|
| Тип запитів | SQL-рядки в @Query | Dart-методи + sql-файли |
| Кодогенерація | floor_generator (build_runner) | drift_dev (build_runner) |
| Реактивність | Stream з DAO | Вбудований Stream API + автооновлення |
| Складність | Низька (знайомий SQL) | Середня (власний DSL) |
| Міграції | Ручні SQL-скрипти | Автоматичні + ручні |
| Сумісність | Android, iOS, macOS | Android, iOS, Web, macOS, Linux |
Floor — вибір команд, вже знайомих з SQL та Android Room. Якщо розробники звикли писати SQL-запити вручну і хочуть мінімальну обгортку над SQLite — Floor дає типізацію без вивчення нового DSL. Він також простіший у налагодженні, оскільки згенерований код читабельний та передбачуваний.
Drift дає більш потужну реактивність і підтримує більше платформ. Якщо додаток активно використовує Stream для оновлення UI, вимагає складних запитів з JOIN та підзапитами або збирається під веб — Drift кращий. Однак його поріг входу вищий через необхідність вивчення власного DSL.
Floor будується навколо анотацій. Нижче наведено повний приклад Entity, DAO та Database для додатку-списку завдань. Після запуску build_runner згенеровані класи готові до використання.
Клас TaskEntity з анотацією @Entity маппиться на таблицю task. Поле з @primaryKey стає первинним ключем. Інтерфейс TaskDao містить методи для операцій з таблицею — кожен метод анотований @Query, @Insert, @Update або @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);
}
Абстрактний клас з анотацією @Database зв'язує Entity та DAO. Метод databaseBuilder створює екземпляр бази. Після виклику build база готова: Floor відкриває SQLite-файл, застосовує міграції та повертає DAO для роботи.
@Database(version: 1, entities: [TaskEntity])
abstract class AppDatabase extends FloorDatabase {
TaskDao get taskDao;
}
// Використання
final database = await $FloorAppDatabase.databaseBuilder('app.db').build();
final taskDao = database.taskDao;
final tasks = await taskDao.getAllTasks();
Floor підтримує повернення Stream з DAO-методів. При будь-яких змінах у таблиці Stream випускає новий список. Це інтегрується з StreamBuilder у Flutter — UI автоматично оновлюється при додаванні, зміні або видаленні записів.
@Query('SELECT * FROM TaskEntity ORDER BY priority DESC')
Stream<List<TaskEntity>> watchAllTasks();
// У 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 підтримує версіонування бази даних через параметр version в анотації @Database. При зміні Entity (додаванні або видаленні полів) потрібно збільшити версію та додати міграцію. Міграція — це Dart-функція, яка отримує транзакцію та виконує SQL-запити ALTER TABLE.
Припустимо, у версії 2 ми додали поле dueDate у TaskEntity. Міграція виконується SQL-запитом ALTER TABLE. Якщо міграція не вказана, Floor викликає MigrationStrategy, де можна задати fallback (наприклад, перестворення таблиці з втратою даних).
Floor не надає вбудованого мок-фреймворку, але базу даних можна легко замінити в тестах. Створіть inMemoryDatabaseBuilder — він створює SQLite-базу в пам'яті, ідентичну за схемою продакшну. Після кожного тесту очищайте дані через deleteDatabase для ізоляції тестових сценаріїв.
Floor підтримує транзакції через анотацію @transaction на DAO-методі. Всередині транзакції виконуються кілька запитів послідовно з гарантією відкату при помилці. Пакетна вставка через @Insert з параметром 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();
Часті запитання
sqflite вимагає ручного написання SQL-запитів та маппінгу ResultSet в об'єкти. Floor генерує цей код автоматично: ви описуєте Entity та DAO, а типізовані методи повертають готові Dart-об'єкти. Floor також перевіряє SQL-запити на етапі компіляції через анотації.
Floor не має вбудованих анотацій для зв'язків (ForeignKey, @Relation), як Room. Зв'язки реалізуються через ручні SQL JOIN-запити в @Query. Для складних реляційних схем краще розглянути Drift з його вбудованою підтримкою відношень.
Floor дозволяє включити callback callback при створенні DatabaseBuilder — в нього передається екземпляр sqflite.Database, на який можна повісити логер. Альтернативно використовуйте floor_doctor для візуалізації схеми та даних у dev-режимі.
Floor використовує sqflite, який не працює у веб-оточенні. Для вебу потрібна окрема збірка з sqlite3 через WASM. У поточній версії Floor офіційно підтримує Android, iOS та macOS. Для вебу використовуйте Drift з sqlite3-адаптером.
Floor не має вбудованого кешування — кожен запит виконується до SQLite. Для кешування повторюваних запитів використовуйте шар Repository з in-memory кешем (наприклад, dart_cache). Floor лише генерує код для роботи з SQLite, не додаючи надбудов над ним.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також