Veri Geçişi
Şema değişiklikleri ve sürüm güncellemeleri için veri geçiş stratejileri uygulayın
Veri Geçişi
Isar; koleksiyon, alan veya indeks ekleyip kaldırdığınızda şemaları otomatik olarak geçirir. Ancak bazen verileri de dönüştürmek isteyebilirsiniz. Isar keyfi kısıtlar getirmemek için dahili çözüm sunmaz, çünkü ihtiyacınıza uygun geçiş mantığını yazmak oldukça kolaydır.
Bu örnekte tüm veritabanı için tek bir sürüm kullanıyoruz. Geçerli sürümü SharedPreferences ile saklıyor ve hedef sürümle karşılaştırıyoruz. Sürümler eşleşmiyorsa veriyi geçiriyor ve sürümü güncelliyoruz.
Esnek Sürümleme
Her koleksiyona ayrı sürüm verip bağımsız olarak da geçirebilirsiniz.
Şema Evrimi Örneği
Doğum günü alanı olan bir kullanıcı koleksiyonumuz olduğunu düşünelim. Uygulamanın 2. sürümünde, kullanıcıları yaşa göre sorgulamak için ek bir doğum yılı alanına ihtiyaç duyuyoruz.
@collection
class User {
Id? id;
late String name;
late DateTime birthday;
}@collection
class User {
Id? id;
late String name;
late DateTime birthday;
short get birthYear => birthday.year;
}Sorun şu ki mevcut kullanıcı modellerinde birthYear alanı boş kalacaktır çünkü 1. sürümde yoktu. birthYear alanını doldurmak için veriyi geçirmek gerekir.
Uygulama
Geçerli Sürümü Kontrol Et
SharedPreferences ile veritabanı sürümünü takip edin ve geçiş gerekip gerekmediğini belirleyin.
Geçişi Gerçekleştir
Tüm kayıtları dolaşıp yeni alanları güncelleyin.
Sürümü Güncelleyin
Kaydedilen sürüm numarasını güncelleyerek geçişin tamamlandığını işaretleyin.
import 'package:isar_plus/isar_plus.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() async {
final dir = await getApplicationDocumentsDirectory();
final isar = Isar.open(
schemas: [UserSchema],
directory: dir.path,
);
await performMigrationIfNeeded(isar);
runApp(MyApp(isar: isar));
}
Future<void> performMigrationIfNeeded(Isar isar) async {
final prefs = await SharedPreferences.getInstance();
final currentVersion = prefs.getInt('version') ?? 2;
switch(currentVersion) {
case 1:
await migrateV1ToV2(isar);
break;
case 2:
// Sürüm ayarlanmamışsa (yeni kurulum) veya zaten 2 ise
// geçiş gerekmez
return;
default:
throw Exception('Unknown version: $currentVersion');
}
// Sürümü güncelle
await prefs.setInt('version', 2);
}
Future<void> migrateV1ToV2(Isar isar) async {
final userCount = await isar.users.count();
// Tüm kullanıcıları aynı anda yüklememek için sayfalıyoruz
for (var i = 0; i < userCount; i += 50) {
final users = await isar.users
.where()
.offset(i)
.limit(50)
.findAll();
await isar.writeAsync((isar) async {
// birthYear getter olduğu için güncelleme yapmamıza gerek yok
await isar.users.putAll(users);
});
}
}En İyi Uygulamalar
Performans Dikkati
Çok fazla veri geçirmeniz gerekiyorsa UI thread'ini yormamak için arka plan izolatı kullanmayı düşünün.
Sayfalama
Bellek sorunu yaşamamak için kayıtları her zaman 50-100'lük bloklar halinde işleyin:
for (var i = 0; i < totalCount; i += batchSize) {
final batch = await collection.where().offset(i).limit(batchSize).findAll();
// Blok üzerinde işlem yap...
}Hata Yönetimi
Geçiş mantığını try-catch içine alın ve rollback stratejilerini değerlendirin:
try {
await migrateV1ToV2(isar);
await prefs.setInt('version', 2);
} catch (e) {
// Hata logla ve eski sürümde kal
print('Migration failed: $e');
// Sürümü güncelleme
}Sürüm Yönetimi
Sürüm takibi için enum kullanmayı düşünün:
enum DatabaseVersion {
v1(1),
v2(2),
v3(3);
const DatabaseVersion(this.value);
final int value;
}Geçiş Testleri
Geçiş mantığını yayından önce kapsamlı şekilde test edin:
void testMigration() async {
// V1 verisiyle test DB oluştur
// Geçişi çalıştır
// V2 veri bütünlüğünü doğrula
}Son Güncelleme