web-dev-qa-db-fra.com

Tentative illégale d'établir une relation 'xyz' entre des objets dans différents contextes

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

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?

41
Alex Reynolds

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.

67
Alex

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 :)

9
Kenneth John

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!

4
shripad20

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

1
Tim
book *book = [mainContext ........]   //Get book from default context

NSManagedObjectID *objectId = [book objectID];

Book *tmpBook = [tmpContext objectWithID:objectId]; //Now book has the legal relationship
0
Elangovan

Version rapide ...

context.insert(objectFromOtherContext)
0
Justin Domnitz