ios objective-c core-data core-data-migration

ios - Datos principales: mezcla ligera y migración personalizada



objective-c core-data (2)

Si puede volver a obtener datos de un servidor o algo así, la mejor manera de solucionar esto es eliminar su modelo anterior e inmediatamente volver a crear uno nuevo con la estructura actual. Está incrustado en una clase singleton y se llama cada vez que se debe crear un nuevo managedobjectcontext. Mi código para esto es el siguiente:

- (NSManagedObjectContext *)managedObjectContext { if (__managedObjectContext != nil) { return __managedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [__managedObjectContext setPersistentStoreCoordinator:coordinator]; } return __managedObjectContext; } - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (__persistentStoreCoordinator != nil) { return __persistentStoreCoordinator; } NSURL *storeURL = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:@"YOURDB.sqlite"]; NSError *error = nil; __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { if (error.code == 134100) { if ( [[NSFileManager defaultManager] fileExistsAtPath: [storeURL path]] ) { NSDictionary *existingPersistentStoreMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType: NSSQLiteStoreType URL: storeURL error: &error]; if ( !existingPersistentStoreMetadata ) { // Something *really* bad has happened to the persistent store [NSException raise: NSInternalInconsistencyException format: @"Failed to read metadata for persistent store %@: %@", storeURL, error]; } if ( ![[self managedObjectModel] isConfiguration: nil compatibleWithStoreMetadata: existingPersistentStoreMetadata] ) { if (![[NSFileManager defaultManager] removeItemAtURL: storeURL error: &error] ) { NSLog(@"*** Could not delete persistent store, %@", error); abort(); } else { [__persistentStoreCoordinator addPersistentStoreWithType: NSSQLiteStoreType configuration: nil URL: storeURL options: nil error: &error]; } } } } else { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } return __persistentStoreCoordinator; }

Así que tengo la versión 1 de mi aplicación Core Data en App Store y ahora comencé a trabajar en la versión 2.

Tengo algunos pequeños cambios en mi modelo de base de datos y algunos códigos personalizados que necesito ejecutar después de esos cambios para completar la actualización de la versión 1 a la versión 2.

Puedo usar la migración liviana de Core Data para lidiar con el cambio de modelo, y puedo ejecutar mi código personalizado después de que la migración haya terminado.

El problema es que no estoy seguro de lo que sucederá en el futuro, cuando construya la versión 3,4,5 ...

supongamos que este es el caso:
la versión 1 a la versión 2: use una migración ligera
Versión 2 a la versión 3: use migración personalizada con mapeo de modelos
versión 3 a la versión 4: use la migración ligera de nuevo
y así..

No estoy seguro de cómo crear un mecanismo que se ocupe de esta combinación de migraciones livianas y personalizadas.
No pude encontrar ningún código en línea o en los documentos de Core Data que hablan sobre este tema, me refiero a que este es un problema muy común para la mayoría de las aplicaciones de Core Data, ¿existen ejemplos de mejores prácticas para este problema?


Dos métodos están escritos a continuación:

  1. Personalmente, me gusta este método, ya que es genial genio IMO, se puede decir por el detalle de mi explicación por qué estoy tan entusiasmado con este método. Este método ha sido escrito en el libro de segunda edición de datos centrales de Marcus Zarra. Es una implementación de un proceso automático de migración progresiva para uso pesado y ligero.

  2. Un método que ideé para una posible implementación después de que el OP preguntara si había una manera de evitar tener que usar modelos de mapeo para cada actualización de migración

Método 1 Aquí es donde entra en juego la migración progresiva. Crea modelos de mapeo para cada actualización de versión que se tratará entre dos versiones de modelo. Un modelo de mapeo le dirá al administrador de migración cómo mapear una versión anterior del almacén de datos a la nueva versión del almacén de datos. Entonces, un modelo de mapeo requiere una source y un destination .

A continuación, tiene tantos modelos de asignación necesarios que cubrirán todos los incrementos de actualización de la versión. Entonces, si tiene 4 versiones, tendrá 3 modelos de mapeo que ayudarán a la transición entre cada actualización de la versión. Al final los tendrá nombrados: V1toV2MappingModel , V2to3MappingModel , V3toV4MappingModel .

En cada modelo de mapeo, puede alternar las opciones para que el administrador de migración sepa cómo desea migrar. Ya sea a través de una política personalizada o una migración de copia normal. Entonces, usted dice que para v1 a v2 necesita una migración ligera, simplemente seleccione el modelo de mapeo apropiado, luego use el editor de modelo / mapeo para hacer las conexiones / mapeos deseados entre atributos antiguos a nuevos atributos y si se requiere una migración personalizada , luego vaya al modelo de mapeo correcto, elija el mapeo de entidad de producto para el que desea personalizar la migración, luego en el inspector de entitymapping verá que puede aplicar una política de migración personalizada, solo copie el nombre de su política de migración. por ejemplo, MigrationPolicyV2toV3 ya que es esa versión particular que desea personalizar.

Entonces, en la imagen de arriba puede ver en el lado izquierdo en el nombre del modelo de mapeo que es para la Versión 1 a la Versión 2. Observe que el mapeo de atributos para el ProductToProduct entidades ProductToProduct está vacío, en el medio. Esto se debe a que si mira a la derecha de la imagen en el inspector de entity mapping donde dice Custom Policy , coloque el nombre de mi política de migración. Esto le permite al administrador de migración conocer (durante el proceso de migración) cómo mapear los atributos y valores del origen al destino (versión 1 a versión 2) y lo sabe debido a la política de migración ingresada. Esto también hace que el type valor cambie a personalizado. permitiéndole saber que va a haber una migración personalizada cuando se trata del ProductToProduct entidades ProductToProduct .

Luego debe definir en su política de migración lo que determinará cómo desea copiar los valores. Aquí es donde haces tus cosas personalizadas.

Como puede ver en la imagen de arriba, es la política de migración personalizada que he establecido para el ProductToProduct entidades ProductToProduct . Notarás que no estoy haciendo nada personalizado, todo esto podría haberse hecho sin la política de migración y podría haberse logrado simplemente haciendo una migración de copia (migración liviana) ajustando algunos valores en el entityMapping inspector y ajustando los valores de Attribute mapping en la imagen anterior. Solo hice todo este material personalizado de política migratoria solo como un ejercicio para que pueda aprender y estar preparado para el futuro, simplemente INCLEMENTO. Alguna vez necesité hacer una pesada migración. Mejor aprenderlo ahora que más tarde oye;)

Eso es todo por hacer cosas personalizadas. Le sugiero que lea la siguiente referencia del desarrollador de Apple en NSEntityMigrationPolicy y los métodos necesarios para hacer más cosas personalizadas, de modo que sepa cómo tener control total durante el proceso de migración cuando una actualización de revisión en particular requiera una migración personalizada o total.

Y para cualquier migración personalizada / pesada, en mi caso utilizo una migration policy para poder hacer algunos cambios en el código personalizado durante la migración de V2 a V3 en mi almacén de datos, entonces creas algo llamado ''política de migración'' para que ESE modelo de mapeo se adherirá a las reglas de migración personalizadas que especifique.

Y simplemente aplica todas las transiciones / mapeos apropiados para cada modelo de mapeo, de modo que el administrador de migración sepa cómo actualizar de una tienda a la siguiente.

Todo lo que necesita es un código recursivo que examinará los metadatos de la tienda existente para determinar si es compatible con la versión más reciente y, si no es así, realizará una migración recursiva automáticamente siguiendo las reglas de cada uno. modelo de mapeo a medida que se actualiza a través de las versiones hasta que la tienda esté actualizada con la versión actual.

De esta forma, puede acomodar a todos los usuarios con cualquier versión y actualizarlos a la tienda de la versión actual. Entonces, si un usuario está en la versión 1, recursivamente pasará de V1 a V2, luego migrará a v3 hasta su versión actual. Lo mismo se aplica si el usuario tiene otra versión.

Esto significa que tomará un poco más de tiempo en el proceso de migración, pero es una buena forma de migrar a todos sus usuarios sin importar qué versión tengan.

Para encontrar este código de migración progresiva, necesita leer un libro llamado Core Data 2nd Edition - Data storage and management for iOS, OS X, and iCloud , Capítulo 3 Versioning and Migration capítulo 3.6 Progressive Data Migration (An Academic Exercise) de páginas 54 to 59 .

Le explica el código y le explica paso a paso cómo escribir progressivelyMigrateURL:ofType:toModel:error: method. Una vez que haya escrito el método con él, él le dirá cómo llamar a este método al inicio de la aplicación para que sus usuarios también puedan migrar sus tiendas de manera progresiva.

Entonces, probablemente debas escribir el método primero, luego seguir mis pasos arriba o puedes leer las políticas de migración en los subcapítulos anteriores.

Prácticamente aprendí todo esto en las últimas 48 horas y lo tengo todo listo y funcionando ahora. Capaz de hacer migraciones livianas para algunas versiones y luego migraciones personalizadas para mis otras versiones, todo hecho automáticamente.

Método 2: otra solución, aunque más engorrosa IMO: siempre puede tener una configuración de migración ligera teniendo en cuenta que aparentemente puede lograr situaciones complejas incluso con una migración ligera. Pero en los casos en que se requiere una gran migración para una actualización de versión específica, siempre puede hacer declaraciones si puede verificar la tienda actual, y si y ÚNICAMENTE si la versión actual de la tienda persistente coincide con una actualización donde se requiere una gran migración, luego le dice al administrador de migración que realice una migración pesada y que siga un modelo de asignación con una política de migración solo para esa instancia y luego reanude la migración ligera si hay más actualizaciones de la versión que hacer para obtener la tienda persistente en la versión del modelo más reciente .