Migrando do Isar v3 para o Isar Plus v4
Atualizar os pacotes legados isar 3.x para isar_plus (v4) é uma mudança incompatível de formato de arquivo. O núcleo da v4 grava metadados diferentes e não consegue abrir um banco criado com a v3, resultando em erros como:
VersionError: The database version is not compatible with this version of Isar.
A correção é exportar os dados existentes com o runtime antigo e importá-los em um banco novo do Isar Plus. Os passos abaixo detalham o processo.
Visão geral da migração
- Publique (ou mantenha) uma build que ainda dependa de
isar:^3.1.0+1para conseguir ler os arquivos legados. - Adicione
isar_pluseisar_plus_flutter_libsao lado dos pacotes antigos enquanto migra. - Rode novamente o gerador para que os esquemas sejam compilados contra as APIs da v4.
- Copie todos os registros da instância v3 para uma nova instância do Isar Plus.
- Apague os arquivos legados e remova as dependências antigas assim que a cópia terminar.
Se você não precisa dos dados antigos, basta excluir o diretório da v3 e começar com um banco limpo. O restante deste guia mostra como preservar os registros.
Atualize as dependências lado a lado
Mantenha o runtime legado até o fim da cópia e só então adicione o novo:
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
Os dois pacotes expõem os mesmos símbolos do Dart, então importe-os com aliases durante a migração:
import 'package:isar/isar.dart' as legacy;
import 'package:isar_plus/isar_plus.dart' as plus;
Gere novamente os esquemas para a v4
O Isar Plus inclui o gerador dentro do pacote principal. Execute o builder para emitir os novos helpers e adaptadores:
dart run build_runner build --delete-conflicting-outputs
Pausa para corrigir qualquer erro de compilação (por exemplo, campos Id? devem virar int id ou usar Isar.autoIncrement). O guia de migração da API resume as mudanças principais:
writeTxn()->writeAsync()ewriteTxnSync()->write()txn()->readAsync()etxnSync()->read()- IDs devem se chamar
idou receber@id; o auto-incremento agora usaIsar.autoIncrement @enumeratedvirou@enumValue- Objetos embutidos substituem a maior parte dos links legados
Copie os dados
Crie uma rotina de migração pontual (por exemplo em main() antes de iniciar o app, ou em um bin/migrate.dart). O padrão é:
- Abra o banco legado com o runtime da v3.
- Abra uma nova instância v4 em outro diretório ou com outro nome.
- Percorra cada coleção em páginas, adapte ao novo esquema e faça
putno novo banco. - Marque a migração como concluída (SharedPreferences, arquivo local ou feature flag) para evitar execuções duplicadas.
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 para o 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),
)),
);
});
}
}
Dica: mantenha funções de mapeamento (como
_mapStatus) ao lado da rotina para tratar renomeações de enums, remoção de campos ou limpeza de dados em um só lugar.
Se a coleção for enorme, execute o loop em um isolate ou serviço em segundo plano para não travar a UI. O mesmo vale para objetos embutidos e links: carregue com a API legada e persista com o novo esquema.
Garanta que só rode uma vez em produção
Enquanto os dois runtimes estiverem no app, todo cold start pode tentar migrar de novo se você não controlar com uma flag. Persista um estado para rodar a cópia apenas uma vez por instalação:
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));
}
Em vez de um booleano, você pode salvar um número de versão (por exemplo 3 para legacy e 4 para Isar Plus) se prever futuras migrações. Em desktop ou servidor, um arquivo .migrated ao lado do diretório do banco também funciona.
Limpeza
Depois de copiar todas as coleções:
- Salve uma flag (por exemplo
prefs.setBool('migratedToIsarPlus', true)) para impedir novas execuções. - Apague os arquivos legados manualmente ou com
plus.Isar.deleteDatabase(name: 'legacy', directory: directoryPath, engine: plus.IsarEngine.isar). - Remova
isareisar_flutter_libsdopubspec.yaml. - Renomeie o novo banco para o nome/diretório original, se necessário.
Somente depois de ter certeza de que ninguém abre mais o build legado publique uma versão que dependa apenas de isar_plus.
Solução de problemas
VersionErrorainda aparece: confirme que os arquivos da v3 foram apagados antes de abrir a instância v4. WAL/LCK antigos podem preservar o cabeçalho legado.- Chaves primárias duplicadas: IDs na v4 precisam ser inteiros únicos e não nulos. Use
Isar.autoIncrementou gere chaves próprias durante a cópia. - Gerador falhou: execute
dart pub cleanantes debuild_runnere verifique se não hápart '...g.dart';faltando. - Precisa reverter: como a migração escreve em um banco separado, você pode descartar os arquivos novos e manter os legados até que a cópia concluída esteja validada.
Seguindo estes passos, os usuários podem sair direto de um build isar 3.x para uma versão isar_plus sem perda de dados.