J'utilise l'exemple d'application CoreDataBooks
d'Apple comme base pour extraire des données dans un contexte d'objet géré secondaire en arrière-plan, puis pour fusionner ces données dans le contexte d'objet géré principal.
Les données que je récupère sont une entité Book
avec une relation un à un avec une entité Owner
(appelée "propriétaire"). L'entité Owner
a une relation à plusieurs sur Book
(appelés "livres").
Mes données sont un document XML de la forme:
<Owner>
<Name>alexpreynolds</Name>
<ID>123456</ID>
</Owner>
<Books>
<Book>Book One</Book>
<Book>Book Two</Book>
...
<Book>Book N</Book>
</Books>
Book One
à Book N
sont associés à une Owner
("alexpreynolds, 123456"
).
J'analyse ceci dans une instance Owner
et une NSMutableSet
composée de Book
instances.
Lorsque j'essaie de sauvegarder la première fois, les sauvegardes sont correctes et les données fusionnées s'affichent dans la vue tableau.
Lors de la deuxième sauvegarde, toutefois, lorsque le contenu XML contient un nouveau livre, cela ne fonctionne pas.
Voici ce qui se passe:
Je tente ensuite de charger un document XML contenant une nouvelle variable Book
qui ne figure pas déjà dans le contexte de l'objet géré principal. La nouvelle Book
utilise la même Owner
que celle associée aux autres Book
s.
J'ai des routines qui sélectionnent cet unique objet géré Owner
(que j'ai déjà dans mon contexte d'objet géré principal) et l'unique Book
qui est non trouvé dans le MOC principal.
À partir de cela, je crée un nouvel objet Book
dans le MOC secondaire et je règle sa relation "owner
" pour qu'elle pointe sur l'unique Owner
trouvé dans le MOC principal.
Lorsque je sauvegarde, j'obtiens l'erreur suivante:
*** Terminating app due to uncaught
exception 'NSInvalidArgumentException',
reason: 'Illegal attempt to establish a
relationship 'owner' between objects in
different contexts
(source = <Book: 0x7803590>
(entity: Book; id: 0x7802ae0 <x-coredata:///
Book/t527F06B2-3EB5-47CF-9A29-985B0D3758862>
; data: {
creationDate = 2009-10-12 06:01:53 -0700;
name = nil;
nameInitial = nil;
operations = (
);
owner = nil;
type = 0;
}) ,
destination = <Owner: 0x78020a0> (entity:
Owner; id: 0x3a56f80 <x-coredata://043AF2F0-1AD0-
4078-A5E8-E9D7071D67D1/Owner/p1> ; data: {
books = "<relationship fault: 0x7801bf0 'books'>";
displayName = alexpreynolds;
ownerID = 123456;
}))'
Comment créer une nouvelle entité Book
dans le MOC secondaire afin de pouvoir encore l'associer à une Owner
préexistante dans le MOC principal?
Vous ne pouvez pas avoir de relations entre des objets dans différents contextes d'objet géré. Une façon de contourner ce problème consiste donc à placer l'objet dans le contexte de l'objet géré.
Par exemple:
NSManagedObject *book = // get a book in one MOC
NSManagedObject *owner = // get an owner in a different MOC
[[owner mutableSetValueForKey:@"books"] addObject:[owner.managedObjectContext objectWithID:[book objectID]]];
Donc, ce que vous faites est en fait d'extraire la Book
dans le même contexte d'objet géré avec owner
. Gardez toutefois à l'esprit que cela n'est possible que si book
a déjà été enregistré. Le contexte de l'objet géré va rechercher l'objet dans le magasin persistant, il doit donc être enregistré en premier.
J'ai eu le même problème et cette phrase m'a aidé à résoudre l'erreur.
Vous ne pouvez pas avoir de relations entre objets dans différents contextes d'objet gérés . Une façon de contourner ce problème consiste donc à placer l'objet Dans le contexte de l'objet géré.
Voici mon code (j'ai remplacé les variables pour le faire fonctionner pour vous):
// Have the owner object and get the managedObjectContext
Owner *owner = [[DataFunctions alloc] getCurrentOwner];
NSManagedObjectContext *context = [owner managedObjectContext];
// Create a book and use the manageObjectContext of owner
Book *book = [NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:context];
[newQuote setValue: "Book Title" forKey:@"title"];
[newQuote setOwner:owner];
J'espère que ça aide :)
Ici, vous essayez d’établir une relation entre deux objets qui sont récupérés/créés avec un contexte différent. Les données de base ne vous permettront pas d'établir de telles relations. Pour ce faire, vous devez extraire le deuxième objet (avec lequel vous essayez d'établir une relation) avec le contexte du premier objet avec objectID. Vous devriez maintenant pouvoir établir une relation entre ces deux objets. Par exemple:
MagicalRecord.saveWithBlock({[unowned self] (localContext: NSManagedObjectContext!) in
let user = User.MR_createEntityInContext(localContext)!
.....
.....
}) //here local context stores data on end of block itself
MagicalRecord.saveWithBlock({[unowned self] (localContext: NSManagedObjectContext!) in
let address = Address.MR_createEntityInContext(localContext)!
.....
.....
let user = localContext.objectWithID(self.user!.objectID) as! User
user.address = address
})
J'espère que ceci vous aidera!
Comme le dit l'erreur, vous n'êtes pas autorisé à avoir une relation dans un objet Core Data dont la valeur est définie sur un autre objet placé dans un contexte différent. Une façon de contourner ce problème consiste à attendre qu'après avoir enregistré le nouvel objet et l'avoir fusionné dans le contexte principal, puis définissez la relation owner
comme il convient (puisque les deux objets se trouvent maintenant dans le même contexte, cela ne pose aucun problème). .
book *book = [mainContext ........] //Get book from default context
NSManagedObjectID *objectId = [book objectID];
Book *tmpBook = [tmpContext objectWithID:objectId]; //Now book has the legal relationship
Version rapide ...
context.insert(objectFromOtherContext)