Que dois-je faire pour que Core Data migre automatiquement les modèles?

96

J'ai lu la documentation sur la migration automatique / légère pour les modèles Core Data - mais j'ai des problèmes de mise en œuvre.

Si je comprends bien, l'application devrait remarquer que le modèle dont elle dispose et le modèle qui existe déjà sur un appareil ne sont pas les mêmes. Si vous n'avez ajouté que des attributs ou des relations et des modifications simples similaires, le modèle doit être mis à niveau automatiquement.

Des pointeurs - dois-je définir quelque chose dans Xcode?

Grouchal
la source

Réponses:

138

J'ai maintenant découvert que c'est assez simple - une fois que vous savez où chercher.

Dans mon AppDelegate, j'ai configuré le NSPersistentStoreCoordinator - et vous devez ajouter quelques options à cela pour lui dire de gérer la migration automatique:

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:

[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,

[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

NSError *error;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
    // Handle error
    NSLog(@"Problem with PersistentStoreCoordinator: %@",error);
}

Ensuite, vous devez faire un petit truc dans xCode:

  1. Sélectionnez votre fichier xcdatamodel
  2. Sélectionnez le menu Conception en haut - puis Modèle de données - puis choisissez Ajouter une version de modèle
  3. Votre fichier xcdatamodel sera alors déplacé dans un nouveau répertoire avec le même nom que votre fichier xcdatamodel mais avec l'extension xcdatamodeld - il y aura un deuxième fichier dans ce répertoire avec un 2 dans le nom. Sélectionnez le nouveau fichier puis Design-> Data Model-> Set Current Version ( dans Xcode 4, vous faites cela )
  4. Si vous avez déjà apporté les modifications qui ont rendu votre projet incompatible, supprimez ces modifications du fichier xcdatamodel d'origine. Si vous n'avez pas encore apporté les modifications, modifiez simplement le fichier 2.xcdatamodel (celui que vous venez de créer dans la version actuelle).
  5. Désormais, lorsque vous installez cette version sur un appareil doté de l'ancien modèle, il mettra automatiquement à niveau ce modèle vers le nouveau modèle.

Cela semble génial et aussi simple que je le voulais - mais je pense que vous devez être prudent pendant le développement lorsque vous modifiez un modèle - sinon vous devrez créer une nouvelle version pour chaque changement.

Je pense que ce que je vais faire, c'est que je conserverai tous les fichiers modifiés, puis une fois que je serai prêt à déployer ma mise à jour, je supprimerai tous les fichiers intermédiaires et je déploierai simplement avec les modèles les plus anciens et les plus récents.


MISE À JOUR (15/07/2011):

Merci à @ rockstarberlin d' avoir signalé qu'il existe une documentation mise à jour sur Apple:

Xcode 4: Définition de la version actuelle d'un modèle d'objet géré

Mise à jour: 19/08/2013 meilleur lien:

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmModelFormat.html

Grouchal
la source
Je suggérerais de lire le Guide de migration et de gestion des versions des données de base, disponible dans la visionneuse de documents Xcode et sur developer.apple.com.
Hunter
1
Je n'ai pas trouvé la réponse là-dedans simplement - il a fallu un certain temps pour savoir comment faire.
Grouchal
NSInferMappingModelAutomaticallyOption fonctionne bien, mais uniquement pour les mappages simples, comme la modification du nom d'un attribut. Pour tout ce qui est plus compliqué (relations, suppression ou ajout d'entités), vous devrez ajouter un modèle de mappage. Si Xcode se plaint que NSInferMappingModelAutomaticallyOption n'est pas déclaré, ajoutez #import <CoreData / CoreData.h> à votre fichier d'en-tête de délégué d'application.
Elise van Looij le
J'ai ajouté quelques entités à mon modèle et j'ai obtenu la tristement célèbre erreur "Le modèle utilisé pour ouvrir le magasin est incompatible avec celui utilisé pour créer le magasin". Votre solution l'a résolu! Merci beaucoup!
Karsten Silz
1
Consultez la réponse de Santthosh ci-dessous si vous obtenez l'erreur «impossible de fusionner des modèles avec deux entités différentes nommées» après avoir suivi ces instructions.
benvolioT
14

C'était incroyablement utile. La documentation Apple était - comme d'habitude - malheureusement incomplète. Je recommande de faire une construction propre, car j'ai rencontré une erreur "Impossible de fusionner les modèles avec deux entités différentes xxx" lorsque j'ai exécuté pour la première fois après avoir effectué ces modifications. La construction propre l'a corrigé.

Scott signifie
la source
Une version propre a également résolu mes problèmes.
jrainbow
6

La réponse de Grouchal est parfaite ... mais si vous avez toujours le "Impossible de fusionner les modèles avec deux entités différentes xxx" même après avoir nettoyé la compilation plusieurs fois ... Vous pourriez avoir des problèmes avec la façon dont le managedObjectModel est chargé. Jetez un œil à celui-ci ... ce qui m'a aidé à le réparer.

principaux problèmes de migration des données

Santthosh
la source
3

De plus, si vous êtes tombé sur ce message, comme je l'ai fait, après avoir obtenu l'erreur "Le modèle utilisé pour ouvrir le magasin est incompatible avec celui utilisé pour créer le magasin" et que vous ne faites que déboguer à l'aide du simulateur et que vous souhaitez remplacer complètement le ancien modèle installé, vous pouvez simplement réinitialiser l'application Simulator ou supprimer votre application du simulateur fonctionnerait probablement également.

Il ne m'est pas venu à l'esprit d'essayer cela avant de lire les articles ici, à quel point j'ai réalisé que j'avais installé l'application dans le simulateur, puis que j'avais changé le modèle, provoquant l'erreur d'exécution susmentionnée.

Dreyln
la source
1

Pour faire suite à la réponse de Santthosh, j'ai pensé que je publierais l'extrait de code ici à la place. Vous devez créer votre managedObjectModel avec initWithContentsOfURL:au lieu de cela, mergedModelFromBundles:sinon vous obtiendrez une erreur:

Impossible de fusionner des modèles avec deux entités différentes XXX et XXX

Si votre fichier de modèle est nommé "Model", voici comment créer le managedObjectModel:

NSString *path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"];
NSURL *momURL = [NSURL fileURLWithPath:path];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL]; 

Crédit à cet article de blog .

samvermette
la source
1

J'ai eu ce problème pendant des années et j'ai essayé toutes ces réponses en vain. Aujourd'hui, j'ai finalement compris ce que je faisais de mal. Problème très simple, mais je l'ai négligé. Lors de la création d'une version plus récente du modèle de données, si vous AJOUTEZ des colonnes, assurez-vous de les marquer comme OPTIONNELLES. Si vous ne le faites pas, la migration simple ne fonctionnera pas car les nouvelles valeurs de colonne ne seront pas renseignées.

Dès que je me suis assuré que mes nouvelles colonnes avaient coché "facultatif", j'ai réessayé la migration et cela a fonctionné.

Brain2000
la source
1

Je suis tombé sur ce message à cause d'un problème différent, mais l'erreur était " La configuration du modèle utilisée pour ouvrir le magasin est incompatible avec celle qui a été utilisée pour créer le magasin. "

Voici mon problème et la solution. Dans mon modèle, j'utilisais des configurations . J'avais certaines des entités stockées dans un fichier et les autres dans un deuxième fichier. (J'ai des valeurs par défaut qui pourraient périodiquement avoir besoin d'être téléchargées, et ce serait une douleur incroyable de les fusionner dans l'ensemble). Quoi qu'il en soit, j'ai créé une nouvelle entité. Le programme semblait bien fonctionner, mais chaque fois que je quittais, j'obtenais l'erreur ci-dessus.

La solution était de regarder mes configurations, de réaliser que j'avais une entité qui n'était actuellement dans aucune des configurations et de l'ajouter à une. Fonctionne comme un rêve.

Cela ne résoudra pas le problème du PO. Mais peut-être qu'une personne frustrée qui atterrit ici via Google sera dans le bateau dans lequel j'étais :)

Le Cappy
la source
0

iOS 4.0+

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"model" withExtension:@"momd"];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
Stian Høiland
la source
0

Modification mineure des super instructions de @ Grouchal ci-dessus pour la version 5 de Xcode:

Ancien: 2. Sélectionnez le menu Conception en haut - puis Modèle de données - puis choisissez Ajouter une version de modèle

Version 5+: 2. Sélectionnez le menu Editeur, puis Ajouter la version du modèle…, saisissez le nom de votre version et Basé sur le modèle (sélectionnez votre modèle d'origine dans la liste)

PGSeattle
la source