2009-10-12 2 views
35

Я использую пример приложения Apple CoreDataBooks в качестве основы для вытягивания данных во вторичный контекст управляемого объекта в фоновом режиме, а затем слияние этих данных в первичный управляемый объект контекст.Нелегальная попытка установить связь «xyz» между объектами в разных контекстах

Данные, которые я вытягиваю, являются объектами Book с отношением к одному с объектом Owner (так называемый «владелец»). Объект Owner имеет отношение «многие» к Book (так называемые «книги»).

Мои данные представляют собой XML-документ в виде:

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

Book OneBook N через ассоциированы с одним Owner ("alexpreynolds, 123456").

Я разобрал это в примере Owner и NSMutableSet, составленном из Book экземпляров.

Когда я пытаюсь сэкономить в первый раз, он сохраняет штраф, и объединенные данные отображаются в виде таблицы.

Во втором сохранении, однако, когда содержимое XML содержит новую книгу, оно не работает.

Вот что происходит:

Я затем попытаться загрузить в документ XML, который содержит новый Book уже не в контексте основного управляемого объекта. В новом Book используется тот же Owner, что и для других Book с.

У меня есть процедуры, которые забрать этот уникальный Owner управляемый объект (который я уже есть в моей основной контекст управляемого объекта) и уникальный Book, который не найдены в первичном МОС.

Исходя из этого, я создаю новый Book объект на вторичном MOC, и я поставил его «owner» отношений, чтобы указать на уникальную Owner я нашел в первичных МОС.

Когда я сохранить, я получаю следующее сообщение об ошибке:

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

Как создать новый Book объект на вторичном MOC, так что я все еще могу связать его с уже существующим Owner в первичной MOC?

ответ

63

Вы не можете иметь отношения между объектами в разных контекстах управляемых объектов. Таким образом, один из способов обойти это - привести объект в контекст управляемого объекта.

Например:

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

Так что вы делаете на самом деле выборки в Book в том же контексте управляемого объекта с owner. Имейте в виду, что это возможно только в том случае, если book уже сохранен. Контекст управляемого объекта будет искать объект в постоянном хранилище, поэтому он должен быть сохранен первым.

+0

Спасибо за это! Я работал с Core Data в фоновом потоке GCD, поэтому должен был быть фон NSManagedObject, который я забыл использовать для вставки родительского объекта, поэтому он использовал основной поток NSManagedObject! В любом случае, спасибо! :) – runmad

1

Как говорится в ошибке, вам не разрешено иметь отношения в одном объекте Core Data, значение которого установлено на другой объект, хранящийся в другом контексте. Один из способов, которыми вы можете обойти это, - подождать, пока вы сохраните новый объект и не слейте его обратно в основной контекст, затем установите соответствующие отношения owner (так как оба объекта теперь находятся в одном и том же контексте, с этим нет проблем) ,

+0

После примера Core Data Books вторичный MOC освобождается после слияния. Если я вместо этого сделаю вторичную переменную MOC переменной экземпляра, первичный владелец MOC обращается к книгам вторичного MOC, который дает сообщение об ошибке. Если у меня есть вторичный MOC-владелец, который ссылается на книги во вторичном MOC, когда я сливаюсь, у меня теперь есть дубликаты экземпляров владельца, что неверно. В идеале я мог бы общаться с существующим владельцем. Если у вас есть время, не могли бы вы объяснить свой ответ чуть подробнее? –

8

У меня была та же проблема, и это предложение помогло мне решить эту ошибку.

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.

Вот мой код (я заменил переменные, чтобы сделать его работу для вас):

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

Я надеюсь, что это помогает :)

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

Здесь вы пытаетесь установить связь между двумя объектами, которые извлекаются/создаются с другим контекстом. Основные данные не позволят вам установить такие отношения. Чтобы добиться этого, вы должны получить второй объект (вы пытаетесь установить связь) с контекстом первого объекта с идентификатором объекта. Теперь вы должны установить связь между этими двумя объектами. Например:

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

Надеюсь, это вам поможет!

 Смежные вопросы

  • Нет связанных вопросов^_^