2009-10-12 9 views
35

Ich verwende Apples CoreDataBooks Beispielanwendung als Grundlage für das Ziehen von Daten in einen sekundären verwalteten Objektkontext im Hintergrund und das anschließende Zusammenführen dieser Daten in das primäre verwaltete Objekt Kontext.Illegaler Versuch, eine Beziehung 'xyz' zwischen Objekten in verschiedenen Kontexten zu erstellen

Die Daten, die ich einziehe, ist eine Book Einheit mit einer Eins-zu-Eins-Beziehung mit einer Owner Einheit (genannt "Besitzer"). Die Owner Entität hat eine zu viele Beziehung mit der Book ("Bücher" genannt).

Meine Daten ein XML-Dokument in der Form:

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

Book One durch Book N mit einem Owner ("alexpreynolds, 123456") zugeordnet sind.

Ich analysiere dies in eine Owner Instanz und eine NSMutableSet bestehend aus Book Instanzen.

Wenn ich versuche, das erste Mal zu speichern, speichert es gut und die zusammengeführten Daten werden in der Tabellenansicht angezeigt.

Beim zweiten Speichern, wenn der XML-Inhalt jedoch ein neues Buch enthält, funktioniert es nicht.

Hier ist, was passiert:

ich dann in einem XML-Dokument zu laden versuchen, ein neues Book nicht bereits in dem primären verwaltete Objektkontext enthält. Die neue Book verwendet dieselbe Owner als die, die mit den anderen Book s zugeordnet ist.

Ich habe Routinen, die dieses einzigartige Owner verwaltete Objekt auswählen (die ich bereits in meinem primären verwaltete Objektkontext habe) und die einzigartigen Book die nicht gefunden im primären MOC ist.

Daraus erstelle ich ein neues Book Objekt im Sekundär MOC, und ich gesetzt sein „owner“ Beziehung zu den einzigartigen Owner ich in der primären MOC gefunden zu zeigen.

Wenn ich speichere, erhalte ich folgende Fehlermeldung:

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

Wie ich eine neue Book Einheit im Sekundär MOC schaffen kann, so dass ich immer noch mit einem bereits bestehenden Owner im primären zuordnen kann MOC?

Antwort

63

Sie können keine Beziehungen zwischen Objekten in verschiedenen verwalteten Objektkontexten haben. Eine Möglichkeit besteht darin, das Objekt in den Kontext des verwalteten Objekts zu bringen.

Zum Beispiel:

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

Also, was Sie tun, ist eigentlich die Book in demselben verwalteten Objektkontext mit owner holen. Beachten Sie jedoch, dass dies nur möglich ist, wenn book bereits gespeichert wurde. Der Kontext des verwalteten Objekts wird nach dem Objekt im persistenten Speicher suchen, daher muss es zuerst gespeichert werden.

+0

Danke dafür! Ich habe mit Core Data in einem Hintergrund-GCD-Thread gearbeitet, also musste ich ein Hintergrund-NSManagedObject haben, das ich vergessen hatte, das Eltern-Objekt einzufügen, so dass es den Haupt-Thread NSManagedObject! Trotzdem danke! :) – runmad

1

Wie der Fehler sagt, dürfen Sie keine Beziehung in einem Core Data-Objekt haben, dessen Wert auf ein anderes Objekt in einem anderen Kontext festgelegt ist. Sie können dies umgehen, indem Sie warten, bis Sie das neue Objekt gespeichert und wieder in den primären Kontext eingefügt haben, und dann die owner-Beziehung entsprechend festlegen (da sich beide Objekte jetzt im selben Kontext befinden, ist das kein Problem). .

+0

Nach dem Beispiel der Core Data Books wird der sekundäre MOC nach der Zusammenführung freigegeben. Wenn ich stattdessen das sekundäre MOC zu einer Instanzvariable mache, bezieht sich der Besitzer des primären MOC auf Bücher im sekundären MOC, die die Fehlermeldung ausgeben. Wenn ich einen sekundären MOC-Besitzer habe, der auf Bücher im sekundären MOC verweist, habe ich beim Zusammenführen nun doppelte Besitzerinstanzen, was nicht korrekt ist. Im Idealfall wäre ich in der Lage, mit einem bestehenden Besitzer zu verbinden. Wenn Sie Zeit haben, können Sie Ihre Antwort bitte etwas genauer erklären? –

8

Ich hatte das gleiche Problem und dieser Satz half mir, den Fehler zu lösen.

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.

mein Code hier (ich die Variablen ersetzt, um es für Sie arbeiten):

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

Ich hoffe, das :)

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

hilft hier, versuchen Sie zu etablieren eine Beziehung zwischen zwei Objekten, die mit einem anderen Kontext abgerufen/erstellt werden. Core-Daten erlauben es nicht, solche Beziehungen herzustellen. Um dies zu erreichen, sollten Sie das zweite Objekt (mit dem Sie versuchen, eine Beziehung herzustellen) mit dem Kontext des ersten Objekts mit objectID abrufen. Jetzt sollten Sie in der Lage sein, eine Beziehung zwischen diesen beiden Objekten herzustellen. Zum Beispiel:

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

Hoffe, das wird Ihnen helfen!