2009-10-12 6 views
35

Sto utilizzando l'applicazione di esempio CoreDataBooks di Apple come base per inserire dati in un contesto oggetto gestito secondario in background e quindi unire tali dati nell'oggetto gestito primario contesto.Tentativo illegale di stabilire una relazione "xyz" tra oggetti in contesti diversi

I dati che sto inserendo sono un'entità Book con una relazione uno a uno con un'entità Owner (denominata "proprietario"). L'entità Owner ha una relazione a molti con lo Book (chiamato "libri").

miei dati è un documento XML della forma:

<Owner> 
    <Name>alexpreynolds</Name> 
    <ID>123456</ID> 
</Owner> 
<Books> 
    <Book>Book One</Book> 
    <Book>Book Two</Book> 
    ... 
    <Book>Book N</Book> 
</Books> 

Book One attraverso Book N sono associati con un Owner ("alexpreynolds, 123456").

Sto analizzando questo in un'istanza Owner e uno NSMutableSet costituito da istanze Book.

Quando si tenta di salvare la prima volta, vengono salvati correttamente e i dati uniti vengono visualizzati nella vista tabella.

Al secondo salvataggio, tuttavia, quando il contenuto XML contiene un nuovo libro, non funziona.

Ecco cosa succede:

ho quindi tentare di caricare in un documento XML che contiene una nuova Book non già nel contesto oggetto gestito primario. Il nuovo Book utilizza lo stesso Owner come quello associato agli altri Book s.

devo routine che individuano questo unico Owner oggetto gestito (che ho già ho nella mia contesto oggetto gestito primario) e l'unica Book che è non trovato nel MOC primario.

Da questo, ho creare un nuovo oggetto nella Book MOC secondario, e ho impostato la sua relazione "owner" per indicare la unica Owner ho trovato nel MOC primario.

Quando risparmio, ottengo il seguente errore:

*** 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; 
}))' 

Come posso creare un nuovo Book entità nel MOC secondario, in modo che posso ancora associarlo a un pre-esistente Owner nel primario MOC?

risposta

63

Non è possibile avere relazioni tra oggetti in diversi contesti di oggetti gestiti. Quindi un modo per aggirare questo è portare l'oggetto nel contesto dell'oggetto gestito.

Ad esempio:

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]]]; 

Quindi quello che stai facendo è in realtà il recupero della Book nello stesso contesto oggetto gestito con owner. Tieni presente, tuttavia, che ciò è possibile solo se book è già stato salvato. Il contesto dell'oggetto gestito cercherà l'oggetto nell'archivio permanente, quindi deve essere prima salvato.

+0

Grazie per questo! Stavo lavorando con Core Data in un thread GCD in background, quindi dovevo avere uno sfondo NSManagedObject, che avevo dimenticato di usare per inserire l'oggetto genitore, quindi stava usando il thread principale NSManagedObject! Comunque grazie! :) – runmad

1

Come dice l'errore, non è consentito avere una relazione in un oggetto Core Data il cui valore è impostato su un altro oggetto contenuto in un contesto diverso. Un modo per aggirare questo è attendere fino a quando non si salva il nuovo oggetto e lo si fonde nel contesto primario, quindi impostare la relazione owner come appropriato (poiché entrambi gli oggetti sono ora nello stesso contesto, non c'è alcun problema con quello) .

+0

In seguito all'esempio di Core Data Book, il MOC secondario viene rilasciato dopo l'unione. Se invece trasformo il MOC secondario in una variabile di istanza, il proprietario del MOC principale si riferisce ai libri nel MOC secondario, che fornisce il messaggio di errore. Se ho un proprietario MOC secondario che fa riferimento ai libri nel MOC secondario, quando mi unisco ora ho istanze duplicate del proprietario, che non sono corrette. Idealmente sarei in grado di associarmi con un proprietario esistente. Se hai tempo, potresti spiegare la tua risposta in modo più dettagliato? –

8

Ho avuto lo stesso problema e questa frase mi ha aiutato a risolvere l'errore.

You can't have relationships between objects in different managed object contexts. So one way of getting around that is to bring the object into the managed object context.

Ecco il mio codice (ho sostituito le variabili per farlo funzionare per voi):

// 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]; 

Spero che questo aiuta :)

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

NSManagedObjectID *objectId = [book objectID]; 

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

Qui, si sta tentando di stabilire una relazione tra due oggetti che vengono recuperati/creati con un contesto diverso. I dati fondamentali non ti permetteranno di stabilire tali relazioni. Per ottenere ciò, dovresti recuperare il secondo oggetto (stai cercando di creare una relazione con) con il contesto del primo oggetto con objectID. Ora dovresti essere in grado di stabilire una relazione tra questi due oggetti. Ad esempio:

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

Spero che questo ti possa aiutare!