Da Isar v3 a Isar Plus v4
L'aggiornamento dai pacchetti legacy isar 3.x a isar_plus (v4) è una modifica incompatibile del formato dei file. Il core di v4 scrive metadati diversi e non può aprire un database creato con v3, quindi compaiono errori come:
VersionError: The database version is not compatible with this version of Isar.
La soluzione è esportare i dati esistenti con il runtime legacy e importarli in un nuovo database Isar Plus. I passaggi seguenti ti guidano lungo il processo.
Panoramica della migrazione
- Distribuisci (o mantieni) una build che dipenda ancora da
isar:^3.1.0+1per poter leggere i file legacy. - Aggiungi
isar_pluseisar_plus_flutter_libsaccanto ai pacchetti legacy durante la migrazione. - Riesegui il generatore di codice affinché gli schemi compilino contro le API v4.
- Copia ogni record dall'istanza v3 in una nuova istanza Isar Plus.
- Elimina i file legacy e rimuovi le vecchie dipendenze una volta completata la copia.
Se non ti servono i vecchi dati, puoi semplicemente cancellare la cartella v3 e partire da un database vuoto. Il resto della guida si concentra sulla conservazione dei record.
Aggiorna le dipendenze in parallelo
Mantieni il runtime legacy finché la copia non termina, poi aggiungi quello nuovo:
dependencies:
isar: ^3.1.0+1
isar_flutter_libs: ^3.1.0+1
isar_generator: ^3.1.0+1
isar_plus: ^1.1.5
isar_plus_flutter_libs: ^1.1.5
dev_dependencies:
build_runner: ^2.4.10
I due pacchetti espongono gli stessi simboli Dart, quindi importali sempre con alias durante la migrazione:
import 'package:isar/isar.dart' as legacy;
import 'package:isar_plus/isar_plus.dart' as plus;
Rigenera gli schemi per v4
Isar Plus include il proprio generatore all'interno del package principale. Riesegui il builder così da ottenere i nuovi helper e adattatori:
dart run build_runner build --delete-conflicting-outputs
Fermati qui e risolvi gli eventuali errori di compilazione (ad esempio i campi Id? devono diventare int id oppure usare Isar.autoIncrement). La guida di migrazione delle API riassume i cambiamenti fondamentali:
writeTxn()->writeAsync()ewriteTxnSync()->write()txn()->readAsync()etxnSync()->read()- Gli ID devono chiamarsi
ido avere@id; l'auto-incremento ora usaIsar.autoIncrement @enumeratedè diventato@enumValue- Gli oggetti annidati sostituiscono la maggior parte dei vecchi link
Copiare i dati
Crea una routine di migrazione una tantum (per esempio in main() prima di inizializzare l'app o in un bin/migrate.dart). Il modello è questo:
- Apri l'archivio legacy con il runtime v3.
- Apri una nuova istanza v4 in una cartella diversa o con un nome diverso.
- Scorri ogni collezione a pagine, adattala al nuovo schema ed esegui
putnel nuovo database. - Segna la migrazione come completata (SharedPreferences, file locale o feature flag) per non eseguirla due volte.
Future<void> migrateLegacyDb(String directoryPath) async {
final legacyDb = await legacy.Isar.open(
[LegacyUserSchema, LegacyTodoSchema],
directory: directoryPath,
inspector: false,
name: 'legacy',
);
final plusDb = await plus.Isar.open(
[UserSchema, TodoSchema],
directory: directoryPath,
name: 'app_v4',
engine: plus.IsarEngine.sqlite, // o IsarEngine.isar per il core nativo
inspector: false,
);
await _copyUsers(legacyDb, plusDb);
await _copyTodos(legacyDb, plusDb);
await legacyDb.close();
await plusDb.close();
}
Future<void> _copyUsers(legacy.Isar legacyDb, plus.Isar plusDb) async {
const pageSize = 200;
final total = await legacyDb.legacyUsers.count();
for (var offset = 0; offset < total; offset += pageSize) {
final batch = await legacyDb.legacyUsers.where().offset(offset).limit(pageSize).findAll();
await plusDb.writeAsync((isar) async {
await isar.users.putAll(
batch.map((user) => User(
id: user.id ?? plus.Isar.autoIncrement,
email: user.email,
status: _mapStatus(user.status),
)),
);
});
}
}
Suggerimento: tieni le funzioni di mapping (come
_mapStatus) accanto alla routine così puoi gestire rinomini di enum, campi rimossi o pulizia dati in un unico punto.
Se hai collezioni molto grandi, esegui il ciclo in un isolate o servizio in background per non bloccare la UI. Lo stesso schema vale per oggetti incorporati e link: caricali con l'API legacy e salvali con il nuovo schema.
Fallo girare una sola volta in produzione
Quando distribuisci entrambi i runtime, ogni avvio a freddo potrebbe tentare di migrare di nuovo se non lo limiti con un flag. Conserva una versione di migrazione per eseguire la copia una sola volta per installazione:
class MigrationTracker {
static const key = 'isarPlusMigration';
static Future<bool> needsMigration() async {
final prefs = await SharedPreferences.getInstance();
return !prefs.getBool(key).toString().contains('true');
}
static Future<void> markDone() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(key, true);
}
}
Future<void> bootstrapIsar(String dir) async {
if (await MigrationTracker.needsMigration()) {
await migrateLegacyDb(dir);
await MigrationTracker.markDone();
}
final isar = await plus.Isar.open(
[UserSchema, TodoSchema],
directory: dir,
);
runApp(MyApp(isar: isar));
}
Al posto di un booleano puoi salvare una versione numerica dello schema (ad esempio 3 per il legacy e 4 per Isar Plus) se prevedi migrazioni future. Su desktop o server puoi anche scrivere un piccolo file .migrated accanto alla cartella del database.
Pulizia finale
Dopo aver copiato tutte le collezioni:
- Memorizza un flag (per esempio
prefs.setBool('migratedToIsarPlus', true)) per evitare esecuzioni successive. - Elimina i file legacy (manualmente o con
plus.Isar.deleteDatabase(name: 'legacy', directory: directoryPath, engine: plus.IsarEngine.isar)). - Rimuovi
isareisar_flutter_libsdallapubspec.yaml. - Rinomina il nuovo database con il nome/directory originale se necessario.
Pubblica una release che dipende solo da isar_plus solo quando sei certo che gli utenti non aprano più la build legacy.
Risoluzione dei problemi
VersionErrorcontinua ad apparire: assicurati di eliminare i file v3 prima di aprire l'istanza v4. I vecchi file WAL/LCK possono mantenere l'intestazione legacy.- Chiavi primarie duplicate: in v4 gli ID devono essere interi univoci e non nulli. Usa
Isar.autoIncremento genera chiavi personalizzate durante la copia. - Il generatore fallisce: esegui
dart pub cleanprima dibuild_runnere controlla che non manchino direttivepart '...g.dart';. - Serve un rollback: poiché la migrazione scrive in un database separato, puoi eliminare i nuovi file e conservare quelli legacy finché la copia non riesce.
Seguendo questi passaggi, gli utenti possono passare direttamente da una build isar 3.x a una release isar_plus senza perdita di dati.