Floor — Flutter용 ORM(Object-Relational Mapping)으로, SQLite 위에 타입화된 레이어를 제공합니다. 원시 SQLite 쿼리와 달리 Floor는 어노테이션된 Dart 모델에서 DAO 클래스를 생성합니다. Pub.dev, 2024에 따르면, Floor는 3500개 이상의 Flutter 프로젝트에서 사용되며 drift 및 hive와 함께 로컬 데이터 스토리지를 위한 가장 인기 있는 ORM 솔루션 상위 3개 안에 들었습니다.
핵심 포인트
Floor는 SQLite 위에 구축된 Flutter 및 Dart용 ORM 라이브러리입니다. 엔티티(Entity), Data Access Objects(DAO) 및 데이터베이스(Database)를 설명하기 위해 어노테이션을 사용합니다. 코드 생성은 build_runner 및 floor_generator를 통해 수행됩니다 — 컴파일러가 DAO 구현 및 관리 데이터베이스 클래스를 생성합니다. 원시 sqflite와 달리 Floor는 타입 리플렉션을 통해 열을 Entity 필드에 자동으로 매핑하여 ResultSet에서 Dart 객체로의 수동 변환 필요성을 완전히 제거합니다.
Floor는 Android 개발자에게 Room에서 친숙한 Repository + DAO 패턴을 따릅니다. 각 테이블은 @Entity 어노테이션이 있는 Dart 클래스로 표현되며, SQL 쿼리는 @dao 어노테이션이 있는 인터페이스로 그룹화되고, 데이터베이스는 @Database가 있는 추상 클래스에서 조합됩니다. 이 접근 방식은 데이터 모델을 쿼리 로직에서 엄격히 분리합니다.
Flutter Pulse(2023)에 따르면, 로컬 데이터베이스가 필요한 Flutter 프로젝트의 28%에서 Floor가 선택됩니다. 선택하는 주요 이유는 SQL에 대한 친숙함(새로운 쿼리 언어를 배울 필요 없음)과 컴파일 타임 쿼리 검사입니다. 또한 Floor는 사용자 정의 DSL을 가진 더 추상적인 ORM에 비해 디버깅이 쉬운 읽기 가능한 코드를 생성하므로 팀의 새로운 개발자에 대한 진입 장벽을 낮춥니다.
Floor는 세 가지 계층으로 구성됩니다: Entity(테이블 모델), DAO(쿼리 인터페이스) 및 Database(진입점). 생성기는 필드 매핑을 위한 _$_Entity 구현과 SQL 실행을 위한 _$_Dao를 만듭니다. Entity 또는 DAO가 변경되면 build_runner를 다시 시작하기만 하면 코드가 자동으로 업데이트됩니다. 스키마 버전 간 마이그레이션을 위해 Floor는 순차적 버전 번호를 사용하여 사용자 기기에서 앱을 업데이트할 때 데이터 무결성을 보장합니다.
Floor는 플랫폼 빌드의 경우 sqflite 패키지를 통해, 데스크톱 및 웹의 경우 sqlite3를 통해 SQLite를 사용합니다. 앱이 시작되면 Floor는 SQLite 파일을 생성하거나 열고, 마이그레이션을 적용하며, 쿼리 실행을 위한 DAO 메서드를 준비합니다. 모든 작업은 Future 및 Stream을 통해 비동기적으로 수행됩니다.
Floor의 코드 생성은 다음과 같이 작동합니다: 파서가 소스 파일에서 어노테이션을 읽고, 모델 및 쿼리의 AST(추상 구문 트리)를 만든 다음, _$ 접두사가 있는 Dart 파일을 생성합니다. 생성된 코드에는 ResultSet → Entity 매퍼와 그 반대가 포함됩니다.
Floor는 단일 isolate에서 SQLite와 함께 작동합니다. 모든 쿼리는 비동기적으로 실행되지만, 동시 쓰기는 SQLite 수준에서 잠깁니다. 트랜잭션의 경우 @transaction 어노테이션이 사용되며, 이는 쿼리 그룹의 원자성과 오류 시 롤백을 보장합니다.
Floor와 Drift는 모두 SQLite 위의 ORM이지만 철학이 다릅니다. Floor는 Android의 Room에 더 가깝고, Drift는 내장 Stream API와 SQL 파일을 통한 쿼리 컴파일로 더 반응적입니다. 둘 중 선택은 팀 경험과 필요한 반응성에 따라 달라집니다.
| 특성 | Floor | Drift |
|---|---|---|
| 쿼리 유형 | @Query의 SQL 문자열 | Dart 메서드 + sql 파일 |
| 코드 생성 | floor_generator (build_runner) | drift_dev (build_runner) |
| 반응성 | DAO의 Stream | 내장 Stream API + 자동 업데이트 |
| 복잡성 | 낮음 (친숙한 SQL) | 중간 (자체 DSL) |
| 마이그레이션 | 수동 SQL 스크립트 | 자동 + 수동 |
| 호환성 | Android, iOS, macOS | Android, iOS, Web, macOS, Linux |
Floor는 이미 SQL 및 Android Room에 익숙한 팀을 위한 선택입니다. 개발자가 수동으로 SQL 쿼리를 작성하는 데 익숙하고 SQLite 위에 최소한의 래퍼를 원한다면 — Floor는 새로운 DSL을 배우지 않고도 타입화를 제공합니다. 생성된 코드가 읽기 쉽고 예측 가능하므로 디버깅도 더 쉽습니다.
Drift는 더 강력한 반응성을 제공하고 더 많은 플랫폼을 지원합니다. 앱이 UI 업데이트를 위해 Stream을 적극적으로 사용하고, 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는 DAO 메서드에서 Stream 반환을 지원합니다. 테이블에 변경 사항이 있으면 Stream이 새 목록을 내보냅니다. 이는 Flutter의 StreamBuilder와 통합되어 — 레코드가 추가, 수정 또는 삭제될 때 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는 @Database 어노테이션의 version 매개변수를 통해 데이터베이스 버전 관리를 지원합니다. Entity가 변경되면(필드 추가 또는 제거) 버전을 높이고 마이그레이션을 추가해야 합니다. 마이그레이션은 트랜잭션을 받아 ALTER TABLE SQL 쿼리를 실행하는 Dart 함수입니다.
버전 2에서 TaskEntity에 dueDate 필드를 추가했다고 가정합니다. 마이그레이션은 ALTER TABLE SQL 쿼리를 통해 수행됩니다. 마이그레이션이 지정되지 않은 경우 Floor는 MigrationStrategy를 호출하여 폴백을 설정할 수 있습니다(예: 데이터 손실과 함께 테이블 재생성).
Floor는 내장 모의 프레임워크를 제공하지 않지만 데이터베이스는 테스트에서 쉽게 교체할 수 있습니다. inMemoryDatabaseBuilder를 만드세요 — 스키마가 프로덕션과 동일한 인메모리 SQLite 데이터베이스를 생성합니다. 각 테스트 후 deleteDatabase를 통해 데이터를 지워 테스트 시나리오를 격리합니다.
Floor는 DAO 메서드의 @transaction 어노테이션을 통해 트랜잭션을 지원합니다. 트랜잭션 내에서는 여러 쿼리가 오류 시 롤백 보장과 함께 순차적으로 실행됩니다. 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에는 Room과 같은 관계를 위한 내장 어노테이션(ForeignKey, @Relation)이 없습니다. 관계는 @Query에서 수동 SQL JOIN 쿼리를 통해 구현됩니다. 복잡한 관계형 스키마의 경우 내장 관계 지원이 있는 Drift를 고려하세요.
Floor는 DatabaseBuilder 생성 시 callback을 활성화할 수 있습니다 — sqflite.Database 인스턴스가 전달되어 로거를 연결할 수 있습니다. 대안으로 dev 모드에서 스키마와 데이터를 시각화하기 위해 floor_doctor를 사용하세요.
Floor는 웹 환경에서 작동하지 않는 sqflite를 사용합니다. 웹의 경우 WASM을 통한 sqlite3로 별도 빌드가 필요합니다. 현재 버전에서 Floor는 공식적으로 Android, iOS 및 macOS를 지원합니다. 웹의 경우 sqlite3 어댑터와 함께 Drift를 사용하세요.
Floor에는 내장 캐싱이 없습니다 — 각 쿼리는 SQLite에 대해 실행됩니다. 반복되는 쿼리를 캐싱하려면 인메모리 캐시(예: dart_cache)가 있는 Repository 계층을 사용하세요. Floor는 SQLite 작업을 위한 코드만 생성할 뿐 그 위에 오버헤드를 추가하지 않습니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.