Migrer d'Isar v3 vers Isar Plus v4
La mise à jour des paquets hérités isar 3.x vers isar_plus (v4) est un changement incompatible du format de fichier. Le cœur v4 écrit des métadonnées différentes et ne peut pas ouvrir une base créée avec v3 ; vous verrez donc des erreurs comme :
VersionError: The database version is not compatible with this version of Isar.
La solution est d'exporter vos données avec l'ancien runtime puis de les importer dans une nouvelle base Isar Plus. Les étapes ci-dessous détaillent la procédure.
Vue d'ensemble de la migration
- Publiez (ou conservez) une build qui dépend encore de
isar:^3.1.0+1afin de lire les fichiers hérités. - Ajoutez
isar_plusetisar_plus_flutter_libsà côté des anciens paquets pendant la migration. - Relancez le générateur de code pour compiler vos schémas contre les API v4.
- Copiez chaque enregistrement de l'instance v3 vers une nouvelle instance Isar Plus.
- Supprimez les fichiers hérités et retirez les vieilles dépendances une fois la copie terminée.
Si vous n'avez pas besoin des anciennes données, supprimez simplement le répertoire v3 et démarrez avec une base vide. Le reste de ce guide se concentre sur la conservation des enregistrements existants.
Mettre à jour les dépendances en parallèle
Gardez l'ancien runtime jusqu'à la fin de la copie, puis ajoutez le nouveau :
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
Les deux paquets exposent les mêmes symboles Dart, importez-les donc toujours avec des alias pendant la migration :
import 'package:isar/isar.dart' as legacy;
import 'package:isar_plus/isar_plus.dart' as plus;
Régénérer vos schémas pour v4
Isar Plus embarque son générateur dans le paquet principal. Relancez le builder pour produire les nouveaux helpers et adaptateurs :
dart run build_runner build --delete-conflicting-outputs
Faites une pause ici et corrigez toute erreur de compilation (par exemple, les champs Id? doivent devenir des int id ou utiliser Isar.autoIncrement). Le guide de migration d'API récapitule les changements majeurs :
writeTxn()->writeAsync()etwriteTxnSync()->write()txn()->readAsync()ettxnSync()->read()- Les ID doivent s'appeler
idou être annotés avec@id; l'auto-incrément passe parIsar.autoIncrement @enumerateddevient@enumValue- Les objets embarqués remplacent la plupart des anciens liens
Copier les données
Créez une routine de migration ponctuelle (par exemple dans main() avant l'initialisation de l'app ou dans un bin/migrate.dart). Le schéma général est le suivant :
- Ouvrir le magasin hérité avec le runtime v3.
- Ouvrir une nouvelle instance v4 dans un autre dossier ou sous un autre nom.
- Parcourir chaque collection par pages, la mapper vers le nouveau schéma et faire
putdans la nouvelle base. - Marquer la migration comme terminée (SharedPreferences, fichier local ou feature flag) pour éviter une deuxième exécution.
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, // ou IsarEngine.isar pour le core natif
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),
)),
);
});
}
}
Astuce : Gardez les fonctions de mapping (comme
_mapStatus) à côté de la routine afin de gérer renommages d'enums, suppressions de champs ou nettoyage de données au même endroit.
Si vous avez des collections très volumineuses, exécutez la boucle dans un isolate ou un service en arrière-plan pour ne pas bloquer l'UI. Le même schéma s'applique aux objets embarqués et aux liens : chargez-les avec l'API héritée puis persistez-les via le nouveau schéma.
S'assurer qu'elle ne s'exécute qu'une fois en production
Tant que vous livrez les deux runtimes, chaque démarrage à froid risque de relancer la migration, sauf si vous la protégez par un indicateur. Persistez une version de migration pour que la copie ne s'exécute qu'une fois par installation :
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));
}
Plutôt qu'un booléen, vous pouvez stocker une version numérique du schéma (par exemple 3 pour l'ancien et 4 pour Isar Plus) si vous anticipez d'autres migrations. Sur desktop ou serveur, un simple fichier .migrated placé à côté du dossier de base fonctionne aussi.
Nettoyage
Après avoir copié toutes les collections :
- Persistez un indicateur (par exemple
prefs.setBool('migratedToIsarPlus', true)) pour empêcher une nouvelle exécution. - Supprimez les fichiers hérités (manuellement ou via
plus.Isar.deleteDatabase(name: 'legacy', directory: directoryPath, engine: plus.IsarEngine.isar)). - Retirez
isaretisar_flutter_libsdepubspec.yaml. - Renommez la nouvelle base vers le nom ou dossier d'origine si nécessaire.
N'expédiez une version dépendant uniquement de isar_plus que lorsque vous êtes sûr que les utilisateurs n'ouvriront plus la build héritée.
Dépannage
VersionErrorpersiste : vérifiez que vous avez supprimé les fichiers v3 avant d'ouvrir l'instance v4. D'anciens fichiers WAL/LCK peuvent conserver l'en-tête hérité.- Doublons de clés primaires : en v4 les ID doivent être des entiers uniques et non nuls. Utilisez
Isar.autoIncrementou générez vos propres clés lors de la copie. - Le générateur échoue : exécutez
dart pub cleanavantbuild_runneret assurez-vous que toutes les directivespart '...g.dart';sont présentes. - Besoin de revenir en arrière : comme la migration écrit dans une base distincte, vous pouvez jeter les nouveaux fichiers et conserver ceux de v3 tant que la copie n'est pas validée.
Une fois ces étapes en place, vos utilisateurs peuvent passer directement d'une build isar 3.x à une version isar_plus sans perte de données.