Floor — Flutter için ORM (Object-Relational Mapping), SQLite üzerinde tiplendirilmiş bir katman sağlar. Ham SQLite sorgularının aksine Floor, anotasyonlu Dart modellerinden DAO sınıfları üretir. Pub.dev, 2024'e göre, Floor 3500'den fazla Flutter projesinde kullanılmakta ve drift ile hive'ın yanı sıra yerel veri depolama için en popüler üç ORM çözümü arasında yer almaktadır.
Temel Noktalar
Floor, SQLite üzerine inşa edilmiş Flutter ve Dart için bir ORM kütüphanesidir. Varlıkları (Entity), Data Access Objects (DAO) ve veritabanını (Database) tanımlamak için anotasyonlar kullanır. Kod üretimi build_runner ve floor_generator aracılığıyla gerçekleştirilir — derleyici DAO uygulamaları ve bir yönetici veritabanı sınıfı oluşturur. Ham sqflite'ın aksine Floor, tür yansıması yoluyla sütunları otomatik olarak Entity alanlarına eşleyerek ResultSet'ten Dart nesnelerine manuel dönüştürme ihtiyacını tamamen ortadan kaldırır.
Floor, Android geliştiricilerine Room'dan tanıdık gelen Repository + DAO desenini izler. Her tablo @Entity anotasyonuna sahip bir Dart sınıfıyla temsil edilir, SQL sorguları @dao anotasyonuna sahip arayüzlerde gruplanır ve veritabanı @Database anotasyonuna sahip soyut bir sınıfta birleştirilir. Bu yaklaşım, veri modelini sorgu mantığından kesin olarak ayırır.
Flutter Pulse (2023)'e göre, yerel veritabanı gerektiren Flutter projelerinin %28'inde Floor seçilmektedir. Seçilmesinin ana nedenleri SQL'e aşinalik (yeni bir sorgu dili öğrenmeye gerek yok) ve derleme zamanı sorgu denetimidir. Ayrıca Floor, özel DSL'lere sahip daha soyut ORM'lere kıyasla hata ayıklaması kolay, okunabilir kod üretir ve bu da ekipteki yeni geliştiriciler için giriş bariyerini düşürür.
Floor üç katmandan oluşur: Entity (tablo modeli), DAO (sorgu arayüzü) ve Database (giriş noktası). Oluşturucu, alan eşlemesi için _$_Entity uygulamaları ve SQL yürütmesi için _$_Dao oluşturur. Entity veya DAO değiştiğinde, build_runner'ı yeniden başlatmak yeterlidir — kod otomatik olarak güncellenir. Şema sürümleri arasında geçiş için Floor sıralı sürüm numaraları kullanır ve kullanıcı cihazlarında uygulama güncellenirken veri bütünlüğünü garanti eder.
Floor, platform derlemeleri için sqflite paketi ve masaüstü ile web için sqlite3 aracılığıyla SQLite kullanır. Uygulama başladığında, Floor SQLite dosyasını oluşturur veya açar, geçişleri uygular ve sorguları yürütmek için DAO yöntemlerini hazırlar. Tüm işlemler Future ve Stream aracılığıyla eş zamansız olarak gerçekleştirilir.
Floor'da kod üretimi şu şekilde çalışır: ayrıştırıcı, kaynak dosyalardan anotasyonları okur, modellerin ve sorguların AST'sini (Soyut Sözdizimi Ağacı) oluşturur, ardından _$ ön ekine sahip Dart dosyaları üretir. Oluşturulan kod, ResultSet → Entity eşleyicilerini ve tersini içerir.
Floor, tek bir isolate içinde SQLite ile çalışır. Tüm sorgular eş zamansız olarak yürütülür, ancak eş zamanlı yazmalar SQLite düzeyinde kilitlenir. İşlemler için, bir sorgu grubunun atomikliğini ve hata durumunda geri almayı garanti eden @transaction anotasyonu kullanılır.
Hem Floor hem de Drift SQLite üzerinde ORM'dir, ancak felsefe olarak farklılık gösterirler. Floor, Android'in Room'una daha yakındır; Drift ise yerleşik Stream API ve SQL dosyaları aracılığıyla sorgu derlemesiyle daha tepkiseldir. Aralarındaki seçim, ekip deneyimine ve gereken tepkiselliğe bağlıdır.
| Özellik | Floor | Drift |
|---|---|---|
| Sorgu türü | @Query'de SQL dizeleri | Dart yöntemleri + sql dosyaları |
| Kod üretimi | floor_generator (build_runner) | drift_dev (build_runner) |
| Tepkisellik | DAO'dan Stream | Yerleşik Stream API + otomatik güncelleme |
| Karmaşıklık | Düşük (tanıdık SQL) | Orta (kendi DSL'si) |
| Geçişler | Manuel SQL betikleri | Otomatik + manuel |
| Uyumluluk | Android, iOS, macOS | Android, iOS, Web, macOS, Linux |
Floor, zaten SQL ve Android Room'a aşina olan ekipler için seçimdir. Geliştiriciler manuel olarak SQL sorguları yazmaya alışıkmış ve SQLite üzerinde minimum bir sarmalayıcı istiyorlarsa — Floor, yeni bir DSL öğrenmeden tiplendirme sağlar. Oluşturulan kod okunabilir ve öngörülebilir olduğu için hata ayıklaması da daha kolaydır.
Drift daha güçlü tepkisellik sunar ve daha fazla platformu destekler. Uygulama UI güncellemeleri için Stream'i aktif olarak kullanıyorsa, JOIN ve alt sorgularla karmaşık sorgular gerektiriyorsa veya web'i hedefliyorsa — Drift tercih edilir. Ancak, kendi DSL'sini öğrenme gerekliliği nedeniyle giriş bariyeri daha yüksektir.
Floor anotasyonlar etrafında inşa edilmiştir. Aşağıda, bir görev listesi uygulaması için Entity, DAO ve Database'in tam bir örneği verilmiştir. build_runner çalıştırıldıktan sonra, oluşturulan sınıflar kullanıma hazırdır.
TaskEntity sınıfı, @Entity anotasyonuyla task tablosuna eşlenir. @primaryKey'e sahip alan birincil anahtar olur. TaskDao arayüzü, tablo işlemleri için yöntemler içerir — her yöntem @Query, @Insert, @Update veya @Delete ile anotasyonlanmıştır.
@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 anotasyonuna sahip soyut bir sınıf, Entity ve DAO'yu birbirine bağlar. databaseBuilder yöntemi bir veritabanı örneği oluşturur. build çağrıldıktan sonra veritabanı hazırdır: Floor SQLite dosyasını açar, geçişleri uygular ve çalışma için DAO'yu döndürür.
@Database(version: 1, entities: [TaskEntity])
abstract class AppDatabase extends FloorDatabase {
TaskDao get taskDao;
}
// Kullanım
final database = await $FloorAppDatabase.databaseBuilder('app.db').build();
final taskDao = database.taskDao;
final tasks = await taskDao.getAllTasks();
Floor, DAO yöntemlerinden Stream döndürmeyi destekler. Tablodaki herhangi bir değişiklikte, Stream yeni bir liste yayar. Bu, Flutter'daki StreamBuilder ile entegre olur — kayıtlar eklendiğinde, değiştirildiğinde veya silindiğinde UI otomatik olarak güncellenir.
@Query('SELECT * FROM TaskEntity ORDER BY priority DESC')
Stream<List<TaskEntity>> watchAllTasks();
// Flutter widget'nda
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 anotasyonundaki version parametresi aracılığıyla veritabanı sürümlemesini destekler. Entity değiştiğinde (alan ekleme veya kaldırma), sürümü artırmanız ve bir geçiş eklemeniz gerekir. Geçiş, bir işlem alan ve ALTER TABLE SQL sorgularını yürüten bir Dart işlevidir.
Sürüm 2'de TaskEntity'ye bir dueDate alanı eklediğimizi varsayalım. Geçiş, ALTER TABLE SQL sorgusu aracılığıyla gerçekleştirilir. Bir geçiş belirtilmezse Floor, MigrationStrategy'yi çağırır ve burada bir geri dönüş ayarlayabilirsiniz (örneğin, veri kaybıyla tabloyu yeniden oluşturma).
Floor yerleşik bir mock framework sağlamaz, ancak veritabanı testlerde kolayca değiştirilebilir. Bir inMemoryDatabaseBuilder oluşturun — şemada üretimle aynı olan bellekte bir SQLite veritabanı oluşturur. Her testten sonra, test senaryolarını izole etmek için deleteDatabase aracılığıyla verileri temizleyin.
Floor, DAO yöntemlerinde @transaction anotasyonu aracılığıyla işlemleri destekler. Bir işlemin içinde, birden çok sorgu, hata durumunda geri alma garantisiyle sıralı olarak yürütülür. 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();
Sıkça Sorulan Sorular
sqflite, manuel SQL sorgusu yazma ve ResultSet'i nesnelere eşleme gerektirir. Floor bu kodu otomatik olarak üretir: Entity ve DAO'yu tanımlarsınız ve tiplendirilmiş yöntemler kullanıma hazır Dart nesneleri döndürür. Floor ayrıca anotasyonlar aracılığıyla derleme zamanında SQL sorgularını da kontrol eder.
Floor, Room gibi ilişkiler için yerleşik anotasyonlara (ForeignKey, @Relation) sahip değildir. İlişkiler, @Query'de manuel SQL JOIN sorguları aracılığıyla uygulanır. Karmaşık ilişkisel şemalar için, yerleşik ilişki desteğine sahip Drift'i düşünün.
Floor, DatabaseBuilder oluştururken bir callback etkinleştirmeye izin verir — bir kaydedici ekleyebileceğiniz sqflite.Database örneği alır. Alternatif olarak, dev modunda şema ve verileri görselleştirmek için floor_doctor kullanın.
Floor, web ortamında çalışmayan sqflite kullanır. Web için, WASM aracılığıyla sqlite3 ile ayrı bir derleme gerekir. Mevcut sürümde Floor resmi olarak Android, iOS ve macOS'u destekler. Web için sqlite3 adaptörüyle Drift kullanın.
Floor'un yerleşik önbelleklemesi yoktur — her sorgu SQLite'da yürütülür. Tekrarlanan sorguları önbelleğe almak için, bellekte önbellek (örneğin, dart_cache) ile bir Repository katmanı kullanın. Floor, SQLite ile çalışmak için yalnızca kod üretir, üzerine ek yük eklemez.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun