Tengo un proyecto de iOS con una gran base de datos precargada y una pequeña base de datos de usuario (ambas tiendas CoreData SQLite). Las preguntas anteriores sugirieron usar configuraciones para controlar qué entidades se usan con qué tienda. Tengo problemas para conseguir que funcione. Esto es lo que he estado tratando ...CoreData con múltiples almacenes: problemas de configuración
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) return _managedObjectModel;
// set up the model for the preloaded data
NSURL *itemURL = [[NSBundle mainBundle] URLForResource:@"FlagDB" withExtension:@"momd"];
NSManagedObjectModel *itemModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:itemURL];
// set up the model for the user data
NSURL *userDataURL = [[NSBundle mainBundle] URLForResource:@"UserData" withExtension:@"momd"];
NSManagedObjectModel *userDataModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:userDataURL];
// merge the models
_managedObjectModel = [NSManagedObjectModel modelByMergingModels:[NSArray arrayWithObjects:itemModel, userDataModel, nil]];
// define configurations based on what was in each model
WRONG [_managedObjectModel setEntities:itemModel.entities forConfiguration:@"ItemData"];
WRONG [_managedObjectModel setEntities:userDataModel.entities forConfiguration:@"UserData"];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) return _persistentStoreCoordinator;
// preloaded data is inside the bundle
NSURL *itemURL = [[[NSBundle mainBundle] bundleURL] URLByAppendingPathComponent:@"FlagDB.sqlite"];
// user data is in the application directory
NSURL *userDataURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"UserData.sqlite"];
NSManagedObjectModel *mom = self.managedObjectModel;
NSError *error = nil;
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData" URL:itemURL options:nil error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
...
Esto aborta con "El modelo utilizado para abrir la tienda es incompatible con la utilizada para crear el almacén". Al verificar los valores hash en el modelo frente a los valores hash en la tienda, se muestra que son idénticos para las entidades que están en la configuración de ItemData.
Si intento hacer una migración de peso ligero, así: 'Modelo no contiene la configuración 'ItemData:
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData" URL:itemURL options:options error:&error])
falla con 'NSInvalidArgumentException', razón''. Supongo que es porque el proceso de migración liviano está creando un nuevo modelo y no contiene mi configuración.
Basado en algunas sugerencias en otros hilos, he intentado hacer una migración liviana sin la configuración, y luego crear un nuevo coordinador usando la configuración. Este tipo de trabajo funciona, pero agrega tablas a mi archivo .sqlite precargado correspondiente a las entidades de datos de usuario (que no pertenecen) y crea las tablas de datos precargados y las tablas de datos de usuario en el almacén de datos de usuario recién creado. . El resultado final es que las recuperaciones fallan, aparentemente porque están buscando en la tienda equivocada.
NSDictionary *migrationOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
// make a temp persistent store coordinator to handle the migration
NSPersistentStoreCoordinator *tempPsc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
// migrate the stores
if (![tempPsc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:itemURL options:migrationOptions error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
if (![tempPsc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:userDataURL options:migrationOptions error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
// make a permanent store coordinator
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
NSDictionary *readOnlyOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSReadOnlyPersistentStoreOption, nil];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData" URL:itemURL options:readOnlyOptions error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
/*if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"UserData" URL:userDataURL options:nil error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}*/
Y más tarde ...
OSAppDelegate *delegate = [UIApplication sharedApplication].delegate;
NSManagedObjectContext *context = delegate.managedObjectContext;
// sanity check
for (NSPersistentStore *store in context.persistentStoreCoordinator.persistentStores) {
NSLog(@"store %@ -> %@", store.configurationName, store.URL);
NSMutableArray *entityNames = [[NSMutableArray alloc] init];
for (NSEntityDescription *entity in [context.persistentStoreCoordinator.managedObjectModel entitiesForConfiguration:store.configurationName]) {
[entityNames addObject:entity.name];
}
NSLog(@"entities: %@", entityNames);
}
NSFetchRequest *categoryFetchRequest = [[NSFetchRequest alloc] init];
categoryFetchRequest.entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:context];
categoryFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", categoryName];
NSError *error = nil;
Category *category = [[delegate.managedObjectContext executeFetchRequest:categoryFetchRequest error:&error] lastObject];
Esto funciona bien, volviendo al objeto Categoría apropiado nombre, hasta que elimine el comentario de la adición de la segunda tienda. Si hago eso, el resultado de búsqueda vuelve vacío. Los mensajes de diagnóstico NSLog imprimen exactamente lo que espero. Cada tienda está asociada con la configuración correcta, y cada configuración tiene las entidades apropiadas.
¿Alguien puede indicarme el código fuente para una configuración de varias tiendas en funcionamiento, o darme una pista de lo que estoy haciendo mal? ¡Gracias por adelantado!
RESUELTO: El quid de la cuestión era las dos líneas marcadas mal en el primer listado de código. Estaba intentando crear configuraciones programáticamente, pero eso parece ser insuficiente. Si consulta ManagedObjectModel para obtener configuraciones después de hacer esto, haga vea las configuraciones en la lista, y las entidades correctas estén asociadas con esas configuraciones. Sin embargo, parece que se necesita hacer algo más para que PersistentStoreCoordinator pueda usarlos correctamente. Crear las configuraciones en Xcode hace que funcionen.
SEGUIMIENTO: Hay un inconveniente adicional. La solución de ejecutar un pase de migración por separado antes de configurar el coordinador de tienda persistente final funciona muy bien ... en el simulador. En un dispositivo real, los permisos son más estrictos. Si intenta hacer esa migración, falla porque la tienda en el paquete de la aplicación es de solo lectura. La migración parece ser necesaria a menos que consolide sus modelos. Si solo tiene un modelo y la tienda en el paquete de la Aplicación es compatible con él, la migración no es necesaria y funciona utilizando las configuraciones definidas en Xcode.
Otra opción podría ser mover datos al directorio de Documentos antes de intentar la migración. No he verificado que ese enfoque funcione.
Asegúrese de realizar la migración en el directorio del documento de usuario de la aplicación sandbox, que es de lectura/escritura, y no en el paquete de la aplicación en sí. – Sunny
No deseaba mover los datos al directorio de Documentos porque no quiero que los datos (estáticos) sean copiados y contados en contra de la cuota de iCloud del usuario. Pero parece que en iOS 5.0.1 hay una manera de designar archivos para que no se realice una copia de seguridad: http://developer.apple.com/library/ios/#qa/qa1719/_index.html – Aneel
Bueno, usted me inspiró y Después de pasar unas horas para resolver mi problema, escribí un artículo completo sobre esto [aquí] (http://blog.atwam.com/blog/2012/05/11/multiple-persistent-stores-and-seed-data -with-core-data /). Pensé que podría ayudar a otras personas en el futuro. – Wam