Persistent store migration failed missing source managed object model - objective-c

I'm trying to expand my Core Data. So I added a new attribute to my entity and tried using the Automatic Lightweight Migration. But when I'm starting the programm the error Persistent store migration failed missing source managed object model pops up.
Anyone knows what goes wrong?
The relevant part of my AppDelegate.c (in fact I only added NSDictionary *options):
- (NSPersistentStoreCoordinator *) persistentStoreCoordinator {
if (persistentStoreCoordinator) return persistentStoreCoordinator;
NSManagedObjectModel *mom = [self managedObjectModel];
if (!mom) {
NSAssert(NO, #"Managed object model is nil");
NSLog(#"%#:%# No model to generate a store from", [self class], _cmd);
return nil;
}
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *applicationSupportDirectory = [self applicationSupportDirectory];
NSError *error = nil;
if ( ![fileManager fileExistsAtPath:applicationSupportDirectory isDirectory:NULL] ) {
if (![fileManager createDirectoryAtPath:applicationSupportDirectory withIntermediateDirectories:NO attributes:nil error:&error]) {
NSAssert(NO, ([NSString stringWithFormat:#"Failed to create App Support directory %# : %#", applicationSupportDirectory,error]));
NSLog(#"Error creating application support directory at %# : %#",applicationSupportDirectory,error);
return nil;
}
}
NSURL *url = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: #"stats.darx"]];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: mom];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:url
options:options
error:&error]){
[[NSApplication sharedApplication] presentError:error];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
return nil;
}
return persistentStoreCoordinator;
}

You need to use a versioned Managed Object Model, containing both versions of your model. The automatic migration still needs to see both the existing and new versions of your model in order to work out what the differences are, and how to handle them.
The error you quote suggests that your app bundle now contains only your new model (the one you want to use), and not the old one (the one you're trying to migrate from). Go back into your version control system and retrieve the old model, then set up a versioned model containing the old model as v1 and the new one as v2.

Related

Lightweight Migration with RestKit

Apple's docs give the following example for setting up an (automatic) lightweight migration:
NSError *error = nil;
NSURL *storeURL = <#The URL of a persistent store#>;
NSPersistentStoreCoordinator *psc = <#The coordinator#>;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
BOOL success = [psc addPersistentStoreWithType:<#Store type#>
configuration:<#Configuration or nil#> URL:storeURL
options:options error:&error];
if (!success) {
// Handle the error.
}
However I am using RestKit, which handles the creation of the persistant store behind the scenes. A simplified version of my initialisation code looks like this:
// Initialize RestKit
RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:rootURL];
// Create the object store
objectManager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:databaseName
usingSeedDatabaseName:seedDatabaseName
managedObjectModel:nil //Don't need to pass it in. It is infered
delegate:self];
// Create Mappings
...
// Define Relationships
...
// Set Mappings
...
Where should I pass in configuration options given that RestKit creates the persistantStore behind the scenes?
In my understanding RestKit is sitting on top of Core Data. So even when you're using a seeded database and let RestKit assign the object store for the object manager, the sqlite database that's provided by Core Data will be used.
To enable lightweight migration with RestKit, you can use the - (NSPersistentStoreCoordinator *)persistentStoreCoordinator method in the AppDelegate (see this thread)
AppDelegate
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil) return __persistentStoreCoordinator;
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"thenameofyoursqlite.sqlite"];
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(#"Auto migration failed, error %#, %#", error, error.userInfo);
abort();
}
}
You can add these options in RKManagedObjectStore.m, in createPersistentStoreCoordinator method.
For verion 0.10 of RestKit, it is already added, not sure for latest version. But if not already added you can add youself. The final look of the method would be like this.
- (void)createPersistentStoreCoordinator
{
NSAssert(_managedObjectModel, #"Cannot create persistent store coordinator without a managed object model");
NSAssert(!_persistentStoreCoordinator, #"Cannot create persistent store coordinator: one already exists.");
NSURL *storeURL = [NSURL fileURLWithPath:self.pathToStoreFile];
NSError *error;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_managedObjectModel];
// Allow inferred migration from the original version of the application.
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(managedObjectStore:didFailToCreatePersistentStoreCoordinatorWithError:)]) {
[self.delegate managedObjectStore:self didFailToCreatePersistentStoreCoordinatorWithError:error];
} else {
NSAssert(NO, #"Managed object store failed to create persistent store coordinator: %#", error);
}
}
}
I have tested this in my project, by adding 3 new entities and renaming an old entity, and is working perfect without deleting previous app from device.
Hope this helps you.

Syncing an existing Core Data store with iCloud

I am trying to get iCloud to work with my app, which needs to migrate an existing local store to a ubiquitous store, if the user requests it.
After some nosing around Apple dev forums and elsewhere, I have taken this approach, which is not working consistently. I have actually seen it work, but only after several crashes on Device B (which is populated from iCloud).
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil)
return persistentStoreCoordinator;
NSURL *legacyStoreUrl = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:[self activeStoreFilenameUpgraded:NO]]];
NSURL *upgradedStoreUrl = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:[self activeStoreFilenameUpgraded:YES]]];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if ((IOS_VERSION_GREATER_THAN_OR_EQUAL_TO(#"5.0")) && (self.iCloudEnabled)) {
NSPersistentStoreCoordinator* psc = persistentStoreCoordinator;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSDictionary *cloudOptions = nil;
NSDictionary *localOptions = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
NSURL *cloudURL = [fileManager URLForUbiquityContainerIdentifier:#"<CONTAINER ID>"];
NSString *coreDataCloudContent = [[cloudURL path] stringByAppendingPathComponent:[NSString stringWithFormat:#"logs%d",[self activeStoreIndex]]];
if ([coreDataCloudContent length] != 0) {
// iCloud is available
cloudURL = [NSURL fileURLWithPath:coreDataCloudContent];
cloudOptions = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
#"MyAppStore", NSPersistentStoreUbiquitousContentNameKey,
cloudURL, NSPersistentStoreUbiquitousContentURLKey,
nil];
} else {
// iCloud is not available
}
NSError *error = nil;
[psc lock];
if(migrateStore) {
migrateStore = NO;
NSPersistentStore *srcPS = [psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:legacyStoreUrl
options:localOptions
error:&error];
if (![psc migratePersistentStore:srcPS
toURL:upgradedStoreUrl
options:cloudOptions
withType:NSSQLiteStoreType
error:&error]) {
NSLog(#"Error migrating data: %#, %# / %# / %#", error, [error userInfo], legacyStoreUrl, upgradedStoreUrl);
abort();
}
}
else {
if (![psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:upgradedStoreUrl
options:(cloudOptions ? cloudOptions : localOptions)
error:&error]) {
NSLog(#"Unresolved iCloud error %#, %#", error, [error userInfo]);
abort();
}
}
[psc unlock];
[[NSNotificationCenter defaultCenter] postNotificationName:#"RefetchAllDatabaseData" object:self userInfo:nil];
} else {
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
NSError *error = nil;
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:legacyStoreUrl options:options error:&error]) {
// error
abort();
}
}
return persistentStoreCoordinator;
}
iCloud Core Data syncing is terribly broken. A more reliable third-party solution is TICoreDataSync; this fork has support for syncing over iCloud, without relying on iCloud's Core Data sync implementation. It simply uses iCloud to sync files and handles the Core Data object syncing on its own.
I gave up on iCloud Core Data syncing and have been building my app with this library instead; so far it's been working great, with none of the issues I saw with Apple's implementation.
I gave up on iCloud integration, for now at least. I don't feel I can offer my users a reliable syncing solution via iCloud given the erratic Core Data performance. I'm holding out hope for iOS 5.1.
Did you make it work?
Try asking here if not - Weird Errors using CoreData with iCloud
Or give us the solution if yes :)

Error after adding a new core data model version

I added a new model version, and I set the core data model to use that new version, but I get this error when the application tries to start.
"The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store."
I'm guessing the problem is that the current persistent store is the old version of the model. Is there a way to just delete it so it makes a new one? I don't care about saving any of that data.
You have to migrate between versions. According to Apple's docs, if the changes are simple, you can do lightweight migration.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmLightweight.html#//apple_ref/doc/uid/TP40008426-SW1
Adding these options to the NSPersistentStoreCoordinator seemed to work.
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSURL *url = [applicationFilesDirectory URLByAppendingPathComponent:#"YOURAPP.storedata"];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType configuration:nil URL:url options:options error:&error]) {
[[NSApplication sharedApplication] presentError:error];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
return nil;
}
return persistentStoreCoordinator;
In answer to your question, "Is there a way to delete it so it just makes a new one ?"
Yes.
Just change the persistentStoreCoordinator getter in your App Delegate as follows:
- (NSPersistentStoreCoordinator *) persistentStoreCoordinator {
if (persistentStoreCoordinator) return persistentStoreCoordinator;
NSManagedObjectModel *mom = [self managedObjectModel];
if (!mom) {
NSAssert(NO, #"Managed object model is nil");
NSLog(#"%#:%s No model to generate a store from", [self class], (char *)_cmd);
return nil;
}
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *applicationSupportDirectory = [self applicationSupportDirectory];
NSError *error = nil;
if ( ![fileManager fileExistsAtPath:applicationSupportDirectory isDirectory:NULL] ) {
if (![fileManager createDirectoryAtPath:applicationSupportDirectory withIntermediateDirectories:NO attributes:nil error:&error]) {
NSAssert(NO, ([NSString stringWithFormat:#"Failed to create App Support directory %# : %#", applicationSupportDirectory,error]));
NSLog(#"Error creating application support directory at %# : %#",applicationSupportDirectory,error);
return nil;
}
}
NSURL *url = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: #"storedata"]];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: mom];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType
configuration:nil
URL:url
options:nil
error:&error]){
// EDIT: if error opening persistent store, remove it and create a new one
if([[error domain] isEqualToString:#"NSCocoaErrorDomain"] && [error code] == 134100) {
NSLog(#"Core Data model was updated. Deleting old persistent store.");
[[NSFileManager defaultManager] removeItemAtURL:url error:nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType
configuration:nil
URL:url
options:nil
error:&error]){
[[NSApplication sharedApplication] presentError:error];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
return nil;
}
} else {
[[NSApplication sharedApplication] presentError:error];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
return nil;
}
//
}
return persistentStoreCoordinator;
}
Figure out where your app stored the document and put it in the trash.
But as a extended comment you may wish to examine the possibilities around both explicit and implicit migration in NSPersistentStoreCoordinator and the options in.
- (NSPersistentStore *)addPersistentStoreWithType:(NSString *)storeType configuration:(NSString *)configuration URL:(NSURL *)storeURL options:(NSDictionary *)options error:(NSError **)error
Depending how different the versions are you can get it to happen automagically by passing NSMigratePersistentStoresAutomaticallyOption & NSInferMappingModelAutomaticallyOption
theres also
- (NSPersistentStore *)migratePersistentStore:(NSPersistentStore *)store toURL:(NSURL *)URL options:(NSDictionary *)options withType:(NSString *)storeType error:(NSError **)error

core data database is empty test

How can I test if the core data database is empty?
I tried:
NSIndexPath *path1 = [NSIndexPath indexPathForRow:0 inSection:0];
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:path1];
if([[managedObject valueForKey:#"date"] description]!=nil){SOMEFUNCTION}else{SOMEFUNCTION}
Thanks
you have to create a fetchrequest for each entity you use in core data. if the fetchrequest returns without results you don't have objects of this entity stored in your core data.
- (BOOL)coreDataHasEntriesForEntityName:(NSString *)entityName {
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
[request setFetchLimit:1];
NSError *error = nil;
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error];
if (!results) {
LogError(#"Fetch error: %#", error);
abort();
}
if ([results count] == 0) {
return NO;
}
return YES;
}
not perfect I admit but it works
my code:
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:0];
int fufu = [sectionInfo numberOfObjects];
if(fufu!=0){DATABASE IS NOT EMPTY}else{DATABASE IS EMPTY}
if someone know something more efective pls post it
I have these two methods implemented in my appDelegate:
- (NSString *)applicationDocumentsDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (persistentStoreCoordinator != nil)
return persistentStoreCoordinator;
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"YourApp.sqlite"]];
NSLog(#"storeURL: %#", storeUrl);
NSError *error;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error])
{
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be
useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
Typical reasons for an error here include:
* The persistent store is not accessible
* The schema for the persistent store is incompatible with current managed object model
Check the error message to determine what the actual problem was.
*/
}// if
return persistentStoreCoordinator;
}
The storeUrl prints the path to the sqlite database.
If you open this path with a sqlite manager, you're able to see the content of your sql database. I use this SQLite Manager to analyze sqlite databases: SQLite Manager
(You can only use this method on the simulator)

Where to Put Code Configuring Persistent Store for Migration

I have a Mac App already created and distributed on the App Store to many customers, and I need to add an attribute to the Core Data Model. I read the documentation provided by Apple, available here.
However, it gives this block of code to enable automatic migration:
NSError *error;
NSPersistentStoreCoordinator *psc = <#The coordinator#>;
NSURL *storeURL = <#The URL of a persistent store#>;
NSDictionary *optionsDictionary =
[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
forKey:NSMigratePersistentStoresAutomaticallyOption];
NSPersistentStore *store = [psc addPersistentStoreWithType:<#Store type#>
configuration:<#Configuration or nil#>
URL:storeURL
options:optionsDictionary
error:&error];
.. And I have no idea where to put that. Someone mentioned (in another thread) that it goes into a PersistentStoreCoordinator, however, I simply used the default Cocoa App Template with "Use Core Data for Storage" enabled. I had to create my own AppDelegate and never saw anything about a PersistentStoreCoordinator (and still don't. I've tried creating a new app just to check). Any help here? I'm new to Cocoa but my app works perfectly fine without a PersistentStoreCoordinator, which is why I haven't implemented one yet.. I do have an AppDelegate I created, but when I put this code in there it throws many errors. HELP :/
EDIT (for nick): Here is the new code:
And my header file:
Here you go: Core Data relevant header and methods.
Application Delegate Header - Core Data relevant parts
#interface CoreDataFirstStepsAppDelegate : NSObject <UIApplicationDelegate>
{
// ...
#private
NSManagedObjectContext *managedObjectContext_;
NSManagedObjectModel *managedObjectModel_;
NSPersistentStoreCoordinator *persistentStoreCoordinator_;
}
// ...
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
Application Delegate Implementation - Core Data relevant parts
/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext_ != nil) {
return managedObjectContext_;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext_ = [[NSManagedObjectContext alloc] init];
[managedObjectContext_ setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext_;
}
/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created from the application's model.
*/
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSString *modelPath = [[NSBundle mainBundle] pathForResource:#"CoreDataFirstSteps" ofType:#"momd"];
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel_;
}
/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"CoreDataFirstSteps.sqlite"];
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSError *error;
NSURL *storeURL = storeURL;
NSPersistentStoreCoordinator *psc = persistentStoreCoordinator_;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:options
error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
return persistentStoreCoordinator_;
}
/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}