Performance Considerations for Deleting Managed Objects Using the Cascade Rule in Master Data

I searched in SO, but I did not find any suggestions for improving performance when deleting a managed object in Core Data when working with relationships.

The script is pretty simple. enter image description here

As you can see, there are three different objects. Each object is connected in cascade with the following. For example, FirstLevel has a relationship named secondLevels before SecondLevel . The deletion rule from FirstLevel to SecondLevel is Cascade , while the deletion rule from SecondLevel to FirstLevel Nullify . The same rules apply between SecondLevel and ThirdLevel .

When I want to delete the entire graph, I execute the following method:

 NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"FirstLevel" inManagedObjectContext:context]; [fetchRequest setEntity:entity]; NSError *error = nil; NSArray *items = [context executeFetchRequest:fetchRequest error:&error]; [fetchRequest release]; // delete roots object and let Core Data to do the rest... for (NSManagedObject *managedObject in items) { [context deleteObject:managedObject]; } 

Using the Cascade rule, the graph is deleted. This works fast for multiple objects, but reduces performance for many objects. In addition, I think (but I'm not very sure) that this type of deletion performs many round trips to disk, am I wrong?

So my question is this: how can I delete a graph without using the Cascade rule and improve performance, but at the same time maintain consistency in the graphs?

Thanks in advance.

EDIT

I cannot delete the whole file, since I have other objects in my model.

EDIT 2

The code I posted is wrapped in the main method of the NSOperation subclass. This solution eliminates the deletion phase in the background. Since I took advantage of the Cascade Rule , deletion is done semi-automatically. I only FirstLevel root objects, FirstLevel elements, using a for loop inside the published code. So Core Data will do the rest for me. I am wondering if it is possible to perform a semi-automatic delete operation and execute it manually without losing schedule consistency?

+7
source share
2 answers

You cannot do much about the time it takes to move and delete objects in the database. However, you can do this in the background so that the user interface does not block.

For example, something like (the code assumes ARC - and was just printed - not compiled) ...

 - (void)deleteAllLevelsInMOC:(NSManagedObjectContext*)moc { // Create a context with a private queue, so access happens on a separate thread. NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; // Insert this context into the current context hierarchy context.parentContext = context; // Execute the block on the queue of the context context.performBlock:^{ NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"FirstLevel"]; // This will not load any properties - just object id fetchRequest.includesPropertyValues = NO; // Iterate over all first-level objects, deleting each one [[context executeFetchRequest:fetchRequest error:0] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [context deleteObject:obj]; }]; // Push the changes out of the context [context save:0]; }]; } 

Note that you can add a RootLevel object to your data model and give it a one-to-many relationship with first-tier objects. Then (as long as you have only one root object) all you have to do is delete one root object and it will delete everything else inside CoreData. If you have many FirstLevel objects, this will be the way to go.

Alternatively, you can connect your β€œnew” context directly to the persistent store, make changes and view another context for change notifications.

By the way, if you use UIManagedDocument, you get this kind of background for free, because there is already a parent context running in its own queue, and all changes in the main context are transferred to the parent person in order to actually work with the database.

EDIT

You can do this manually, but you must disable the cascade rule. I found that I want CoreData to do as much as possible for me. This reduces my margin of error.

If you are already deleting the background thread, then how do you see performance issues? You must query during this deletion ... which means that you are using a MOC that does all the work.

You should learn a lesson from UIManagedDocument. You must have a MOC that runs in a private queue. He does all the real work. You have a child MOC that simply transfers the work of this work queue.

If you are actually requesting objects that are not in the graph that you are deleting, you can hang them on the serializing properties of the persistent storage coordinator. If so, you should consider either a separate coordinator, or just have two stores.

Thus, you can delete objects in your schedule as much as you want, but at the same time respond to requests for other objects.

+5
source

I usually enable Core Data SQL tracing with -com.apple.CoreData.SQLDebug 1 , as described here: http://useyourloaf.com/blog/2010/3/11/debugging-core-data-on-the-iphone. html This helps to verify that Core Data does what I expect it to do behind the scenes.

Did you make sure that [moc save: ...] takes this long and not the actual fetchrequest choice to retrieve the objects to be deleted? If so, you can get (and then delete) these first-level objects in packages.

+1
source

All Articles