2008-12-19 16 views
4

Le modèle de données de mon application basée sur les données de base (10.5 uniquement) se trouve dans un environnement . Les mises à niveau automatiques de schéma utilisant un modèle de mappage des données de base ne semblent donc pas fonctionner. Il semble que les machines de base de données ne trouvent pas les modèles de données ou le modèle de mappage appropriés lorsqu'elles sont ne font pas partie de l'ensemble principal de l'application. Donc, au lieu d'utiliser la migration automatique , je cours une migration manuellement dans configurePersistentStoreCoordinatorForURL:ofType:... dans ma sous-classe NSPersistenDocument (code ci-dessous). Je migre le magasin persistant dans un fichier temporaire, puis écrase le fichier existant si la migration réussit. Le document présente ensuite une erreur avec le message "Le fichier de ce document a été modifié par une autre application depuis que vous l'avez ouvert ou enregistré." quand j'essaie d'économiser. Comme d'autres sur cette liste ont fait remarquer, cela est dû à ma modification du fichier du document "derrière son dos". J'ai essayé de mettre à jour la date de modification du fichier du document, comme indiqué ci-dessous, mais j'obtiens alors une boîte de dialogue d'erreur avec le message "L'emplacement du document" test.ovproj "ne peut pas être déterminé." quand j'essaie d'économiser. Je suis moins sûr de la raison de cette erreur , mais échanger un message inutile (dans ce cas) pour un autre n'est pas tout à fait ce que je voulais.Migration manuelle du schéma de données de base sans avertissement "document modifié"?

Quelqu'un peut-il offrir quelques conseils? Existe-t-il un moyen de mettre à jour manuellement le schéma pour le stockage persistant d'un document sans déclencher l'un des avertissements (dans ce cas)?

Code

pour la mise à niveau du magasin de données dans mes sous-classes -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]; 

Répondre

1

Je n'ai pas couru dans cette situation particulière, mais j'ai quelques suppositions. Tout d'abord, au lieu d'utiliser -removeItemAtPath: et -moveItemAtPath: lorsque vous souhaitez changer de fichiers, utilisez plutôt la fonction FSExchangeObjects(). NSDocument utilise FSRefs pour suivre le fichier et à moins que vous n'utilisiez FSExchangeObjects(), il se rendra compte qu'il regarde un fichier complètement différent. Deuxièmement, vous pouvez définir manuellement le modèle d'objet géré de votre document en remplaçant -managedObjectModel, en particulier en utilisant la méthode + mergedModelFromBundles: pour charger les modèles à partir de votre infrastructure. Selon les docs, il devrait par défaut fusionner tous les modèles dans le bundle principal et dans tous les frameworks liés, donc cela ne devrait être nécessaire que pour les bundles chargés dynamiquement. Je ne sais pas pourquoi cela ne fonctionne pas pour vous, mais je n'ai pas essayé cela. Pour comprendre quels paquets rechercher, la méthode + bundleForClass: de NSBundle est votre ami.

+0

Il est intéressant de noter que l'erreur readFromURL: ofType: n'a pas résolu le problème. L'utilisation de FSExchangeObjects(), et l'utilisation de [self setFileModificationDate:] avec la date de modification des nouveaux fichiers ont fait l'affaire. Merci pour le pointeur. –

+0

Bon à savoir. J'ai effacé celui-là de ma réponse car ça ne marche pas. –

+0

En effet, l'implémentation par défaut de Document définit la modificationDate avant d'appeler readFromURL: OfType ... – AMTourky

1

Attention aux FSExchangeObjects()! Il ne prend pas en charge tous les types de volumes, voir bSupportsFSExchangeObjects. Je cherche un remplaçant moi-même. Option semble être FSExchangeObjectsCompat de MoreFilesX ou FSReplaceObjects 10.5().

0

10 ans plus tard ... j'ai rencontré le même problème, et avec la nouvelle API pour NSDocument, vous pouvez mettre à jour fileModificationDate du document avec la nouvelle date du fichier mis à jour après avoir fait la migration

migrate() 
if let newModificationDate = try? NSFileManager.defaultManager().attributesOfItemAtPath(url.path!)[NSFileModificationDate] as? NSDate { 
    self.fileModificationDate = newModificationDate 
} 

après que vous pouvez appeler super.configurePersistentStoreCoordinatorForURL...

En effet, NSDocument définit la date de modification du fichier avant même l'appel readFromURL:ofType Voir Document Initialization Message Flow