[Leopard, workaround] Core Data migration for Tiger files

  • 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
  • On Nov 6, 2007, at 7:05 AM, Pierre Bernard wrote:

    > 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.

    There's no way for Core Data to reliably determine the appropriate
    model for a Tiger store, consider that a store may have been created
    by an a run-time data model that was constructed from any number of
    entities from any number of models (or constructed programmatically
    entirely in-memory).

    When version hashes are not available, your best bet is to create a
    migration manager with the appropriate inputs.

    - adam

    > 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
  • Adam,

    Thanks for clarifying this. I can find no word about this in the
    documentation. This is a very serious limitation and should be
    mentioned.

    Is there really no way to infer entity hashes from the tables
    available in the SQLite store at hand?

    Wouldn't it be great if one could specify a default legacy model to
    use on Tiger files?

    Would you consider the below code to be preferable to the workaround I
    posted earlier?

    NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator
    metadataForPersistentStoreOfType:NSSQLiteStoreType URL:url error:error];

    if (sourceMetadata == nil)
    {
      return NO;
    }

    id versionHashes = [sourceMetadata
    objectForKey:@"NSStoreModelVersionHashes"];
    BOOL ok = NO;

    if (versionHashes != nil) {
      NSMutableDictionary *newStoreOptions;

      if (storeOptions == nil)
      {
      newStoreOptions = [NSMutableDictionary dictionary];
      }
      else
      {
      newStoreOptions = [[storeOptions mutableCopy] autorelease];
      }

      [newStoreOptions setObject:[NSNumber numberWithBool:YES]
    forKey:NSMigratePersistentStoresAutomaticallyOption];

      ok = [super configurePersistentStoreCoordinatorForURL:url
                                                         ofType:fileType
                                             modelConfiguration:configuration
                                                    storeOptions:newStoreOptions
                  error:error];
    }
    else {
      NSURL *modelURL = [NSURL fileURLWithPath:[Document
    pathForModelNamed:@"HoudahSpot"]];
      NSManagedObjectModel *sourceModel = [[NSManagedObjectModel alloc]
    initWithContentsOfURL:modelURL];

      NSManagedObjectModel *destinationModel = [self managedObjectModel];


      /*
            To perform the migration, we also need a mapping model.
            We have the source and destination model; NSMapping model provides
    a convenience method to find the correct mapping model from a given
    array of bundles.
            */

      NSArray *bundles = [NSArray arrayWithObject:[NSBundle mainBundle]];

      NSMappingModel *mappingModel = [NSMappingModel
    mappingModelFromBundles:bundles forSourceModel:sourceModel
    destinationModel:destinationModel];

      if (mappingModel == nil)
      {
      // should create a suitable NSError and set in 'error'
      return NO;
      }

      /*
            Move the legacy file out of the way
            */
      NSString *originalPath = [url path];
      NSString *legacyPath = [NSString stringWithFormat:@"%@~",
    originalPath];
      BOOL success = [[NSFileManager defaultManager] movePath:originalPath
    toPath:legacyPath handler:nil];

      if (!success) {
      return NO;
      }

      NSURL *sourceURL = [NSURL fileURLWithPath:legacyPath isDirectory:NO];
      NSURL *destinationURL = [NSURL fileURLWithPath:originalPath
    isDirectory:NO];

      /*
            Create the migration manager and perform the migration
            */

      NSMigrationManager *migrationManager = [[NSMigrationManager alloc]
    initWithSourceModel:sourceModel destinationModel:destinationModel];

      ok = [migrationManager migrateStoreFromURL:sourceURL
    type:NSSQLiteStoreType options:storeOptions
    withMappingModel:mappingModel toDestinationURL:destinationURL
    destinationType:NSSQLiteStoreType destinationOptions:storeOptions
    error:error];

      [migrationManager release];

      if (!ok)
      {
      return NO;
      }

      /*
            Add the new store to the store coordinator and set the file URL
            */
      NSPersistentStoreCoordinator *psc = [[self managedObjectContext]
    persistentStoreCoordinator];

      NSPersistentStore *destinationStore = [psc
    addPersistentStoreWithType:NSSQLiteStoreType
    configuration:configuration URL:destinationURL options:storeOptions
    error:error];

      if (destinationStore == nil)
      {
      return NO;
      }

      [self setFileURL:destinationURL];
    }


    Best,
    Pierre

    On Nov 6, 2007, at 8:50 PM, Adam Swift wrote:

    >
    > On Nov 6, 2007, at 7:05 AM, Pierre Bernard wrote:
    >
    >> 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.
    >
    > There's no way for Core Data to reliably determine the appropriate
    > model for a Tiger store, consider that a store may have been created
    > by an a run-time data model that was constructed from any number of
    > entities from any number of models (or constructed programmatically
    > entirely in-memory).
    >
    > When version hashes are not available, your best bet is to create a
    > migration manager with the appropriate inputs.
    >
    > - adam
    >
    >> 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
    >

    ---
    Pierre Bernard
    http://www.bernard-web.com/pierre
    http://www.houdah.com
  • On Nov 6, 2007, at 12:17 PM, Pierre Bernard wrote:

    > Adam,
    >
    > Thanks for clarifying this. I can find no word about this in the
    > documentation. This is a very serious limitation and should be
    > mentioned.

    I think that's a fair point, please file a documentation enhancement
    request.

    > Is there really no way to infer entity hashes from the tables
    > available in the SQLite store at hand?

    Unfortunately, no.

    > Wouldn't it be great if one could specify a default legacy model to
    > use on Tiger files?

    Hm, maybe, it couldn't hurt to ask ;)

    >
    > Would you consider the below code to be preferable to the workaround
    > I posted earlier?

    Sure, seems like the right way to go.  If there was a custom version
    number (or other custom key/value pair) assigned in your Tiger data
    store metadata you could verify that you're trying to open a
    recognized version of the store file, and from the nit-picky
    department, it'd be nice to revert the original file to it's original
    name (no tilde) if migration fails.

    >
    >
    > NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator
    > metadataForPersistentStoreOfType:NSSQLiteStoreType URL:url
    > error:error];
    >
    > if (sourceMetadata == nil)
    > {
    > return NO;
    > }
    >
    > id versionHashes = [sourceMetadata
    > objectForKey:@"NSStoreModelVersionHashes"];
    > BOOL ok = NO;
    >
    > if (versionHashes != nil) {
    > NSMutableDictionary *newStoreOptions;
    >
    > if (storeOptions == nil)
    > {
    > newStoreOptions = [NSMutableDictionary dictionary];
    > }
    > else
    > {
    > newStoreOptions = [[storeOptions mutableCopy] autorelease];
    > }
    >
    > [newStoreOptions setObject:[NSNumber numberWithBool:YES]
    > forKey:NSMigratePersistentStoresAutomaticallyOption];
    >
    > ok = [super configurePersistentStoreCoordinatorForURL:url
    > ofType:fileType
    > modelConfiguration:configuration
    > storeOptions:newStoreOptions
    > error:error];
    > }
    > else {
    > NSURL *modelURL = [NSURL fileURLWithPath:[Document
    > pathForModelNamed:@"HoudahSpot"]];
    > NSManagedObjectModel *sourceModel = [[NSManagedObjectModel alloc]
    > initWithContentsOfURL:modelURL];
    >
    > NSManagedObjectModel *destinationModel = [self managedObjectModel];
    >
    >
    > /*
    > To perform the migration, we also need a mapping model.
    > We have the source and destination model; NSMapping model
    > provides a convenience method to find the correct mapping model from
    > a given array of bundles.
    > */
    >
    > NSArray *bundles = [NSArray arrayWithObject:[NSBundle mainBundle]];
    >
    > NSMappingModel *mappingModel = [NSMappingModel
    > mappingModelFromBundles:bundles forSourceModel:sourceModel
    > destinationModel:destinationModel];
    >
    > if (mappingModel == nil)
    > {
    > // should create a suitable NSError and set in 'error'
    > return NO;
    > }
    >
    > /*
    > Move the legacy file out of the way
    > */
    > NSString *originalPath = [url path];
    > NSString *legacyPath = [NSString stringWithFormat:@"%@~",
    > originalPath];
    > BOOL success = [[NSFileManager defaultManager]
    > movePath:originalPath toPath:legacyPath handler:nil];
    >
    > if (!success) {
    > return NO;
    > }
    >
    > NSURL *sourceURL = [NSURL fileURLWithPath:legacyPath
    > isDirectory:NO];
    > NSURL *destinationURL = [NSURL fileURLWithPath:originalPath
    > isDirectory:NO];
    >
    > /*
    > Create the migration manager and perform the migration
    > */
    >
    > NSMigrationManager *migrationManager = [[NSMigrationManager alloc]
    > initWithSourceModel:sourceModel destinationModel:destinationModel];
    >
    > ok = [migrationManager migrateStoreFromURL:sourceURL
    > type:NSSQLiteStoreType options:storeOptions
    > withMappingModel:mappingModel toDestinationURL:destinationURL
    > destinationType:NSSQLiteStoreType destinationOptions:storeOptions
    > error:error];
    >
    > [migrationManager release];
    >
    > if (!ok)
    > {
    > return NO;
    > }
    >
    > /*
    > Add the new store to the store coordinator and set the file URL
    > */
    > NSPersistentStoreCoordinator *psc = [[self managedObjectContext]
    > persistentStoreCoordinator];
    >
    > NSPersistentStore *destinationStore = [psc
    > addPersistentStoreWithType:NSSQLiteStoreType
    > configuration:configuration URL:destinationURL options:storeOptions
    > error:error];
    >
    > if (destinationStore == nil)
    > {
    > return NO;
    > }
    >
    > [self setFileURL:destinationURL];
    > }
    >
    >
    >
    > Best,
    > Pierre
    >
    >
    > On Nov 6, 2007, at 8:50 PM, Adam Swift wrote:
    >
    >>
    >> On Nov 6, 2007, at 7:05 AM, Pierre Bernard wrote:
    >>
    >>> 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.
    >>
    >> There's no way for Core Data to reliably determine the appropriate
    >> model for a Tiger store, consider that a store may have been
    >> created by an a run-time data model that was constructed from any
    >> number of entities from any number of models (or constructed
    >> programmatically entirely in-memory).
    >>
    >> When version hashes are not available, your best bet is to create a
    >> migration manager with the appropriate inputs.
    >>
    >> - adam
    >>
    >>> 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
    >>
    >
    > ---
    > Pierre Bernard
    > http://www.bernard-web.com/pierre
    > http://www.houdah.com
    >
    >
    >
previous month november 2007 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Go to today