Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data NSBatchDeleteRequest appears to leave objects in context

Tags:

ios

core-data

I have seen many questions regarding batch deletion in Core Data, but none seem to address my issue.

I am creating an iOS 9 / Swift app using Core Data. At WWDC this year, I attended the Core Data session and saw that I could use NSBatchDeleteRequest to delete large numbers of objects directly from the persistent store. This works for me for some objects but not others, and I think it has something to do with my relationships.

I have an object graph consisting of Subject and Course, where there is a one-to-many relationship. Subjects may own as many courses as they wish.

There is a 'courses' relationship on Subject with a delete rule of Cascade, as I want all courses associated with a subject to be deleted when a subject is deleted.

The inverse is 'subject' on Course, with a delete rule of Nullify. Here, I am a bit confused as to Apple's description of Nullify:

Remove the relationship between the objects but do not delete either object. This only makes sense if the department relationship for an employee is optional, or if you ensure that you set a new department for each of the employees before the next save operation.

That makes it pretty clear, but why would the relationships be deleted but not either object? If I delete a Course, I would like the Course to be deleted and the relationship from the subject to the course to be deleted so that a fault to the deleted Course will not appear in the NSSet on Subject's courses Set.

I want to provide a way for all objects in an entity to be deleted. When I try this by individually fetching and deleting each course, courses are properly deleted and removed from the NSSet of courses on a Subject.

Since I have no idea how many courses will be present and I want to ensure high performance in every situation, I figured I would use batch deletion to delete all courses. The problem is that while utilizing NSBatchDeleteRequest to delete all Subjects works fine, deleting all courses along the way (because of the Cascade rule), trying to delete all Courses using this method appears to leave all objects in place.

I used NSBatchDeleteRequest to delete all Courses, but then when I query the MOC to see what Subjects and Courses still exist, both Courses are still returned and the Subject owning them still has references to them.

In contrast, when I fetch and delete each Course individually, my subsequent fetch properly displays an empty array for all Courses and the 'courses' relationship on the Subject appears to have been properly modified.

Yes, I am saving the context after executing the request. I suppose the context may not be notified of what the store does, but then again deleting all subjects worked great. What is going on here?

like image 922
Matthew Seaman Avatar asked Nov 04 '15 23:11

Matthew Seaman


2 Answers

At the WWDC 2015 session which describes NSBatchDeleteRequest it was explained that "Changes are not reflected in the context". So what you're seeing is normal. Batch updates work directly on the persistent store file instead of going through the managed object context, so the context doesn't know about them. When you delete the objects by fetching and then deleting, you're working through the context, so it knows about the changes you're making (in fact it's performing those changes for you).

If you use NSBatchDeleteResultTypeObjectIDs, you can merge the results of the batch delete back into your context using mergeChangesFromRemoteContextSave:intoContexts: to update your contexts. You could probably also use reset, if you don't have any other managed objects loaded from the context.

like image 149
Tom Harrington Avatar answered Nov 04 '22 18:11

Tom Harrington


I ended up adding the following to take care of the context after the batch delete.

[self.managedObjectContext refreshAllObjects];
like image 28
skantner Avatar answered Nov 04 '22 17:11

skantner