Skip navigation.
 
ml[Leopard, workaround] Core Data migration for Tiger files
FROM : Pierre Bernard
DATE : Tue Nov 06 16:05:56 2007

Hi!

I am seeing problems with Core Data automatic migration reading files 
created using Tiger.

The problem is triggered by the fact that Core Data determines the 
source model to use by looking at the file's metadata. Legacy files my 
lack the required NSStoreModelVersionHashes value. Unfortunately Core 
Data currently (9A581) does not try to derive that value from the 
file's actual content. It just fails to read the file.

My workaround is to let Core Data have a pass at the file. If it 
fails, I check for the missing NSStoreModelVersionHashes value. If it 
is indeed missing, I load appropriate metadata from a PLIST file and 
amend the source file.

Another solution would be to manually instantiate a migration manager 
with the 1.0 model for source model. In the end I decided against this 
solution which involves more code. The below solution will work 
gracefully once the Core Data bug is fixed. I.e. the workaround will 
never again be called.

Best,
Pierre Bernard
Houdah Software s.à r.l.

- (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)url
                                         ofType:(NSString *)fileType
                             modelConfiguration:(NSString *)configuration
                                    storeOptions:(NSDictionary *)storeOptions
                                           error:(NSError **)error
{
   NSMutableDictionary *newStoreOptions;
   
   if (storeOptions == nil)
   {
       newStoreOptions = [NSMutableDictionary dictionary];
   }
   else
   {
       newStoreOptions = [[storeOptions mutableCopy] autorelease];
   }
   
   [newStoreOptions setObject:[NSNumber numberWithBool:YES] 
forKey:NSMigratePersistentStoresAutomaticallyOption];
   
   BOOL ok = [super configurePersistentStoreCoordinatorForURL:url
                                                       ofType:fileType
                                           modelConfiguration:configuration
                                                 storeOptions:newStoreOptions
                                                        error:error];
   
   if (!ok) {
       /*
        Legacy files created under Tiger may lack necessary metadata.
        Add the metadata matching 1.0 files and retry.
        */
       NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator 
metadataForPersistentStoreOfType:NSSQLiteStoreType URL:url error:error];
       id versionHashes = [sourceMetadata 
objectForKey:@"NSStoreModelVersionHashes"];
       
       if (versionHashes == nil) {
           NSString *legacyMetadataPath = [[NSBundle mainBundle] 
pathForResource:@"LegacyMetadata" ofType:@"plist"];
           NSMutableDictionary *metadata = [NSMutableDictionary 
dictionaryWithContentsOfFile:legacyMetadataPath];
           
           [metadata addEntriesFromDictionary:sourceMetadata];
           
           if (![NSPersistentStoreCoordinator setMetadata:metadata 
forPersistentStoreOfType:NSSQLiteStoreType URL:url error:error]) {
               return NO;
           }    
           
           *error = nil;
           ok = [super configurePersistentStoreCoordinatorForURL:url
                                                         ofType:fileType
                                             modelConfiguration:configuration
                                                    storeOptions:newStoreOptions
                                                           error:error];
       }
   }
   
   if (ok)
   {    
       /*
        If all went well, update the metadata
        */
       
       NSURL *fileURL = [self fileURL];
       
       if (fileURL == nil) {
           // File URL is null when writing new files
           fileURL = url;
       }
       
       NSPersistentStoreCoordinator *psc = [[self managedObjectContext] 
persistentStoreCoordinator];
       
       id pStore = [psc persistentStoreForURL:fileURL];
       
       /*
        configurePersistentStoreCoordinatorForURL is called when document 
reopened
        Check for existing metadata to avoid overwriting unnecessarily
        */
       id existingMetadata = [[psc metadataForPersistentStore:pStore] 
objectForKey:(NSString *)kMDItemKeywords];
       
       if (existingMetadata == nil)
       {
           if (![self setMetadataForStoreAtURL:fileURL])
           {
               return NO;
           }
       }
   }
   
   return ok;
}

---
Pierre Bernard
http://www.bernard-web.com/pierre
http://www.houdah.com

Related mailsAuthorDate
ml[Leopard, workaround] Core Data migration for Tiger files Pierre Bernard Nov 6, 16:05
mlRe: [Leopard, workaround] Core Data migration for Tiger files Adam Swift Nov 6, 20:50
mlRe: [Leopard, workaround] Core Data migration for Tiger files Pierre Bernard Nov 6, 21:17
mlRe: [Leopard, workaround] Core Data migration for Tiger files Adam Swift Nov 7, 00:09