I am using Apple's CoreDataBooks
sample application as a basis for pulling data into a secondary managed object context in the background, and then merging that data into the primary managed object context.
The data I am pulling in is a Book
entity with a to-one relationship with an Owner
entity (called "owner"). The Owner
entity has a to-many relationship with the Book
(called "books").
My data is an XML document of the 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
through Book N
are associated with one Owner
("alexpreynolds, 123456"
).
I am parsing this into an Owner
instance and an NSMutableSet
made up of Book
instances.
When I attempt to save the first time, it saves fine and the merged data shows up in the table view.
On the second save, however, when the XML content contains a new book, it doesn't work.
Here's what happens:
I then attempt to load in an XML document that contains a new Book
not already in the primary managed object context. The new Book
is using the same Owner
as that which is associated with the other Book
s.
I have routines that pick out this unique Owner
managed object (which I already have in my primary managed object context) and the unique Book
that is not found in the primary MOC.
From this, I create a new Book
object in the secondary MOC, and I set its "owner
" relationship to point to the unique Owner
I found in the primary MOC.
When I save, I get the following error:
*** 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;
}))'
How do I create a new Book
entity in the secondary MOC, so that I can still associate it with a pre-existing Owner
in the primary MOC?
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.
For example:
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]]];
So what you're doing is actually fetching the Book
into the same managed object context with owner
. Keep in mind, though, that this is only possible if book
has already been saved. The managed object context is going to look for the object in the persistent store, so it has to be saved first.
I had the same problem and this sentence helped me to solve the error.
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.
Here's my code (I replaced the variables to make it work for you):
// 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];
I hope this helps :)
Here, you are trying to establish a relation between two objects which are fetched/created with a different context. Core data won't allow you to establish such relations. To achieve this, you should fetch the second object (you are trying to make a relationship with) with the context of the first object with objectID. Now you should be able to establish a relation between these two objects. For example:
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
})
Hope this will help you!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With