Is there a bulk update operation for all entities in Core Data? - iphone

On the iPhone, Does Core Data have a way to bulk update a field for every instance of an entity that it's storing? Something like
update some_entities set some_count = 0 where some_count > 0
Or do I just have to instantiate every entity, set the value, then save it? (And if that's the answer, how could I do that in a single transaction, assuming the set is too large to fit in memory?)

This is not provided by Core Data, but you could use the makeObjectsPerformSelector:withObject: method of an NSSet or NSArray of your Core Data managed objects.
Pass the setter accessor as the selector and the value as the object.
For example, if the managed objects have an attribute "name" that needs to be set the same for all:
[[fetchedResultsController fetchedObjects] makeObjectsPerformSelector:#selector(setName:) withObject:#"name for all"];
You don't have to have an NSFetchedResultsController. You can use the array from an NSFetchRequest or even the NSSet from a to-many relationship among your Core Data entities.

Core Data isn't a database. If you want to bulk-update the objects, you'll have to fetch them and update the values yourself.
A good way of doing that would be to fetch, say, 100 at a time (using an NSFetchRequest with a fetchLimit set), update them, and then save the managed object context. Lather, rinse, repeat until all the objects are updated.
And, as gerry suggested, if the update you're doing is simple, you can use makeObjectsPerformSelector: to do the update in one line.

No, Core Data doesn't have a bulk update feature. If you're memory-constrained, you might consider redesigning your data model to simplify things; instead of storing an absolute count for each entity, track a master value for a group of entities and store a delta from that value per entity.
Core Data can definitely be frustrating at times for those of us used to thinking in SQL terms.

Related

Is it possible to fetch the data of only one attribute of an Entity in Core Data?

I have an entity in Core Data with multiple attributes. In order to increase the performance of the app, I would like to fetch only one attribute of that entity. Is that possible to do and if so, then how? Or should I just use predicates to fetch the entities that I need and from them access the values of their attributes? Thanks.
It depends on a few things; how many entities are you fetching, do you ever want anything else, what is your real performance problem?
First of all use Instruments to make sure that your problem is actually where you think it is. Core data uses faulting and batching to make it very memory and performance efficient. An entity's attribute data is not brought into memory until it is accessed.
If you really want to only fetch a single attribute from your entities then you can make a fetch request with the propertiesToFetch value set to the attributes you care about. If you do this with a managed object resultType, then AFAIK I know this will use more memory, as it will make all the result objects be a partial fault (with those properties populated) rather than full faults.
If you use the dictionary resultType, then you'll get back no managed objects at all, just an array of dictionaries with the relevant attribute populated.
You can get the single property. Here is the Apple's way

EF 4.1 Commit changes stored in a dictionary

I am using EF 4.1 and in a certain point in my application, I read all the data satisfying a condition from an entity by performing:
context.Entity.Where(<condition>)
then, I iterate over them through a loop, and in specific situations I store some of them into a Dictionary (key value is the Id of the entity, and value is the entire object).
Later, in another point of my app, I read all the objects stored in the dictionary and I update them.
After updating them, I perform SaveChanges on the context, (the context is the same that was used when reading the entire entity and when items where stored in the dictionary.
So at this point, I would like to know if when I perform the savechanges, the data is sent to the database and udpated correctly since I am not sure as the objects modified come from the dictionary and I do not know if EF is so intelligent to know it should update database.
The dictionary as well as the EF context hold references to the objects. As long as the context isn't disposed, it will be able to track the changes.
In other words, putting your entities in a Dictionary (or List or any other means of collection) has no influence on the entities and their context.

iOS / Core Data - Best way to return an array from a NSSet relationship?

I'm creating an app and I'm storing the data using core data. It works fine but I was wondering what's the best way to return a sorted array from an set ?
For example, I have an entity A (Button) that contains a list of entity B (Image). As we all know core data is storing the to-many relationship using an NSSet. But I want to keep track of the initial order so I added a property "order" for that purpose.
The problem is that in my code I need the list of images sorted so in a category file (Button+Create) I created a method like this one :
- (NSArray*)imagesArray
{
return [self.images sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDeacriptorWithKey:#"order" ascending:YES]]];
}
But I don't think that's the best way to do because if a need to access this list from multiple area in my code (different classes) then I need to sort the set x times ...
Is there a way to add an array (property) in my category in order to sort once and then only retrieve the property ?
What are your thoughts about that ?
Thanks
You can add properties to categories:
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html
Here is another example:
How to add properties to NSMutableArray via category extension?
But
Be aware that you will be responsible to observe changes (e.g. via KVO) to the initial coredata NSSet property.
So if changes occur you have to "recalculate" your property properly...
If your target was iOS 5.0 or higher, I would recommend to use Ordered Sets, but due to the fact that you are not, I could imagine using the way described in the links above
I think your approach with order property is correct. I'd rather create a method in my model something like -(NSArray *)sortedItems which would have an NSFetchRequest with appropriate sort descriptor. If you want you can cache the result - save this array in memory. Your NSManagedObject can also have properties that are not stored in the database, just in memory. But I really don't think this is necessary considering the speed and performance of Core Data.

NSFetchRequest on NSOrderedSet?

I have a core data entity called Entry, which has an one-many relationship with entities called Media, which are in an ordered set. I want to run an NSFetchRequest to request a batch size of them, so I can go through them and don't have to load all of them into memory at once. I want to go through them in the order they're in the ordered set though. How can I get them to be in that order?
The best route to go is using an NSFetchedResultsController when you are concerned about memory management when fetching Core Data entities. It will automatically only fetch the objects that you need and minimize the memory footprint.
By fetching all your relevant objects of your ordered set, they should already be in the expected order.

Core Data performance deleteObject and save managed object context

I am trying to figure out the best way to bulk delete objects inside of my Core Data database.
I have some objects with a parent/child relationship. At times I need to "refresh" the parent object by clearing out all of the existing children objects and adding new ones to Core Data. The 'delete all' portion of this operation is where I am running into trouble.
I accomplish this by looping through the children and calling deleteObject for each one.
I have noticed that after the NSManagedObjectContext:Save call following all of the deleteObject calls is very slow when I am deleting 15,000 objects.
How can I speed up this call? Are there things happening during the save operation that I can be aware of and avoid by setting parameters different or setting up my model another way? I've noticed that memory spikes during this operation as well. I really just want to "delete * from".
Thanks.
Supposing that you have in your Core Data model a parent and a child entities, and the parent has a to-many relationship to child called children, you should be able to delete all of the child objects without looping as follows:
NSManagedObject *parentObject = ...;
[parentObject setValue:nil forKey:#"children"];
or using the Core Data generated method
- (void)removeChildren:(NSSet *)value;
NSSet *children = [parentObject valueForKey:#"children"];
[parentObject removeChildren:children];
I am not sure if this will speed up the NSManagedObjectContext save operation. Please let me know about the performances.
Check the relationship dependency graph: a cascade of deletes triggered by the initial deletion will slow things down. If those deletes are unnecessary then change the deletion rule.
according to apple website : http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdCreateMOs.html
it is very simple :
Deleting a managed object is straightforward. You simply send its managed object context a deleteObject: message, passing the object you want to delete as the argument.
[aContext deleteObject:aManagedObject];
This removes the managed object from the object graph. Just as a new object is not saved to the store until the context is saved, a deleted object is not removed from the store until the context is saved.