Migrazione dei dati
Isar migra automaticamente gli schemi del database se aggiungi o rimuovi raccolte, campi o indici. A volte potresti voler migrare anche i tuoi dati. Isar non offre una soluzione integrata perché imporrebbe restrizioni alle migrazioni arbitrarie. È facile implementare la logica di migrazione adatta alle tue esigenze.
Vogliamo utilizzare una singola versione per l'intero database in questo esempio. Utilizziamo le preferenze condivise per archiviare la versione corrente e confrontarla con la versione a cui vogliamo migrare. Se le versioni non corrispondono, migriamo i dati e aggiorniamo la versione.
Suggerimento
Puoi anche assegnare a ciascuna raccolta la propria versione e migrarle individualmente.
Immagina di avere una raccolta di utenti con un campo di compleanno. Nella versione 2 della nostra app, abbiamo bisogno di un campo aggiuntivo per l'anno di nascita per interrogare gli utenti in base all'età.
Versione 1:
@collection
class User {
late int id;
late String name;
late DateTime birthday;
}
Versione 2:
@collection
class User {
late int id;
late String name;
late DateTime birthday;
short get birthYear => birthday.year;
}
Il problema è che i modelli utente esistenti avranno un campo birthYear
vuoto perché non esisteva nella versione 1. Abbiamo bisogno di migrare i dati per impostare il campo birthYear
.
import 'package:isar/isar.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() async {
final dir = await getApplicationDocumentsDirectory();
final isar = await Isar.openAsync(
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:
// If the version is not set (new installation) or already 2, we do not need to migrate
return;
default:
throw Exception('Unknown version: $currentVersion');
}
// Update version
await prefs.setInt('version', 2);
}
Future<void> migrateV1ToV2(Isar isar) async {
final userCount = await isar.users.count();
// We paginate through the users to avoid loading all users into memory at once
for (var i = 0; i < userCount; i += 50) {
final users = await isar.users.where().offset(i).limit(50).findAll();
await isar.writeTxn((isar) async {
// We don't need to update anything since the birthYear getter is used
await isar.users.putAll(users);
});
}
}
Attenzione
Se devi migrare molti dati, prendi in considerazione l'utilizzo di un isolamento in background per evitare sollecitazioni sul thread dell'interfaccia utente.