2009-10-12 21 views
35

Używam aplikacji przykładowej Apple CoreDataBooks jako podstawy do wyciągania danych do dodatkowego obiektu zarządzanego w tle, a następnie łączenia tych danych do głównego zarządzanego obiektu kontekst.Niedozwolona próba nawiązania relacji "xyz" między obiektami w różnych kontekstach

Dane, które przeciągam to jednostka Book z relacją jeden do jednego z jednostką Owner (nazywaną "właścicielem"). Jednostka Owner ma wiele relacji z Book (zwanych "książkami").

Moje dane jest dokumentem XML w postaci:

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

Book One przez Book N są związane z jednym Owner ("alexpreynolds, 123456").

ja parsowania to pod instancji Owner i NSMutableSet składa się z Book przypadkach.

Kiedy próbuję zapisać za pierwszym razem, zapisuje się dobrze, a połączone dane pokazują się w widoku tabeli.

W przypadku drugiego zapisu, gdy zawartość XML zawiera nową książkę, nie działa.

Oto co się dzieje:

ja spróbuje załadować w dokumencie XML, który zawiera nową Book nie już w pierwotnym kontekście zarządzanego obiektu. Nowy Book używa tego samego Owner jako tego, który jest powiązany z innymi Book s.

Mam procedury, które wybierają ten wyjątkowy Owner zarządzanego obiektu (które już mam w moim pierwotnym kontekście zarządzanego obiektu) oraz unikalny Book który jest nie znaleźć w pierwotnej MOC.

Z tego, tworzę nową Book obiekt w średnim MOC i ustawić jej „owner” związek, aby wskazać unikalnego Owner znalazłem w podstawowej MOC.

Kiedy zapisać, pojawia się następujący błąd:

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

Jak utworzyć nowy Book podmiot we wtórnym MOC, tak, że mogę nadal kojarzy się z istniejącej wcześniej Owner w pierwotnym MOC?

Odpowiedz

63

Nie można zawierać relacji między obiektami w różnych kontekstach obiektów zarządzanych. Jednym ze sposobów obejścia tego jest przeniesienie obiektu do kontekstu obiektu zarządzanego.

Na przykład:

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

Więc co robisz jest rzeczywiście pobierania Book do tego samego obiektu zarządzanego kontekście z owner. Pamiętaj jednak, że jest to możliwe tylko wtedy, gdy zapisano już book. Kontekst obiektu zarządzanego będzie szukać obiektu w magazynie trwałym, dlatego musi być zapisany jako pierwszy.

+0

Dzięki za to! Pracowałem z Core Data w wątku GCD w tle, więc musiałem mieć tło NSManagedObject, którego zapomniałem użyć do wstawienia obiektu nadrzędnego, więc używał głównego wątku NSManagedObject! W każdym razie, dzięki! :) – runmad

1

Jak informuje błąd, nie można utrzymywać relacji w jednym obiekcie danych podstawowych, którego wartość jest ustawiona na inny obiekt przechowywany w innym kontekście. Jednym ze sposobów obejścia tego problemu jest poczekać, aż po zapisaniu nowego obiektu i scaleniu go z kontekstem podstawowym, a następnie odpowiednio ustawić relację owner (ponieważ oba obiekty są teraz w tym samym kontekście, nie ma z tym problemu) .

+0

Po wydaniu przykładu Core Data Books, drugorzędny MOC jest zwalniany po wystąpieniu scalenia. Jeśli zamiast tego sprawię, że drugorzędny MOC będzie zmienną instancji, główny właściciel MOC odwołuje się do książek w drugorzędnym MOC, co daje komunikat o błędzie. Jeśli mam wtórnego właściciela MOC, który odnosi się do książek w drugorzędnym MOC, kiedy scalam, mam teraz zduplikowane instancje właściciela, co nie jest poprawne. Idealnie byłoby móc skojarzyć z istniejącym właścicielem. Jeśli masz czas, możesz wyjaśnić swoją odpowiedź nieco bardziej szczegółowo? –

8

Miałem ten sam problem i to zdanie pomogło mi rozwiązać problem.

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.

Oto mój kod (I otrzymuje zmienne, aby pracować dla Ciebie):

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

Mam nadzieję, że to pomoże :)

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

Tutaj staramy się ustalić relacja między dwoma obiektami, które są pobierane/tworzone w innym kontekście. Podstawowe dane nie pozwalają na ustanowienie takich relacji. Aby to osiągnąć, powinieneś pobrać drugi obiekt (próbujesz nawiązać relację) z kontekstem pierwszego obiektu z objectID. Teraz powinieneś być w stanie ustanowić relację między tymi dwoma obiektami. Na przykład:

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

Mam nadzieję, że to Ci pomoże!

Powiązane problemy