The data model for my Core Data document-based app (10.5 only) is in a
framework, so automatic schema upgrades using a Core Data mapping
model don't appear to work. It appears that the Core Data machinery
doesn't find the appropriate data models or mapping model when they
are not in the app's main bundle. So, instead of using the automatic
migration, I'm running a migration manually in
configurePersistentStoreCoordinatorForURL:ofType:...
in my
NSPersistenDocument
subclass (code below). I migrate the persistent
store to a temporary file and then overwrite the existing file if the
migration succeeds. The document then presents an error with the
message "This document's file has been changed by another application
since you opened or saved it." when I try to save. As others on this
list have pointed out, this is due to my modification of the
document's file "behind its back". I tried updating the document's
file modification date, as shown below, but I then get an error dialog
with the message "The location of the document "test.ovproj" cannot be
determined." when I try to save. I'm less sure of the reason for this
error, but trading one unnecessary message (in this case) for an other
isn't quite what I was going for.
Can anyone offer some guidance? Is there a way to manually upgrade the schema for a document's persistent store without triggering one of these (in this case unnecessary) warnings?
code for upgrading the data store in my subclasses
-configurePersistentStoreCoordinatorForURL:ofType:...
:
if(upgradeNeeded) {
NSManagedObjectModel *sourceModel = [NSManagedObjectModel mergedModelFromBundles:VUIModelBundles() orStoreMetadata:meta];
if(sourceModel == nil) {
*error = [NSError errorWithDomain:VUIErrorDomainn ode:VUICoreDataErrorCode localizedReason:BWLocalizedString(@"Unable to find original data model for project.")];
return NO;
}
NSManagedObjectModel *destinationModel = [self managedObjectModel];
NSMigrationManager *migrationManager = [[NSMigrationManager alloc] initWithSourceModel:sourceModel destinationModel:destinationModel];
NSMappingModel *mappingModel = [NSMappingModel mappingModelFromBundles:VUIModelBundles() forSourceModel:sourceModel destinationModel:destinationModel];
if(mappingModel == nil) {
*error = [NSError errorWithDomain:VUIErrorDomain code:VUICoreDataErrorCode localizedReason:BWLocalizedString(@"Unable to find mapping model to convert project to most recent project format.")];
return NO;
}
@try {
//move file to backup
NSAssert([url isFileURL], @"store url is not a file URL");
NSString *tmpPath = [NSString tempFilePath];
id storeType = [meta objectForKey:NSStoreTypeKey];
if(![migrationManager migrateStoreFromURL:url
type:storeType
options:storeOptions
withMappingModel:mappingModel
toDestinationURL:[NSURLfileURLWithPath:tmpPath]
destinationType:storeType
destinationOptions:storeOptions
error:error]) {
return NO;
} else {
//replace old with new
if(![[NSFileManager defaultManager] removeItemAtPath:[url path] error:error] ||
![[NSFileManager defaultManager] moveItemAtPath:tmpPath toPath:[url path] error:error]) {
return NO;
}
// update document file modification date to prevent warning (#292)
NSDate *newModificationDate = [[[NSFileManager defaultManager] fileAttributesAtPath:[url path] traverseLink:NO] bjectForKey:NSFileModificationDate];
[self setFileModificationDate:newModificationDate];
}
}
@finally {
[migrationManager release];
}
}
}
return [super configurePersistentStoreCoordinatorForURL:url ofType:fileType modelConfiguration:configuration storeOptions:storeOptions error:error];