Core Data, how can i find and delete managed objec

2019-08-31 03:27发布

问题:

My app sends a get request to a server with a date (date of last update) to update its content (2 entities in core data, no relationships, all attributes are strings)... most of the time it only receives new content but sometimes it also receives the old content that needs to be updated instead of just inserted. 1 table is pretty straight forward I just get the ids (id from server not form core data) of the items that are going to be updated in an array and I make a fetch of those items and then delete them. After that I insert the updated items as they were new. This is how I delete them:

-(void)deleteOfEntity:(NSString*)entityName theItemsWithIds:(NSArray*)ids{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext: [self managedObjectContext]];
[fetchRequest setEntity:entity];
[fetchRequest setIncludesPropertyValues:NO];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"(id IN %@)", ids]];
NSError *error;
NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
if(fetchedObjects && [fetchedObjects count]>0){
    for (NSManagedObject* toDelete in fetchedObjects) {
        [[self managedObjectContext] deleteObject:toDelete];
    }
}

}

because the attribute name which identifies each item is the ID as usually. But the other table needs 2 attributes to identify items, like a composite key. How do I build up the array of "ids"? an array with arrays of 2 values indicating the composite key? and the predicate? I just want to know if it is possible to do this efficiently, if not I can always fetch all the items and check 1 by 1 but for that I need a for inside another for and that is to ugly. Any help is appreciated.

回答1:

When you designed the database you should have created a unique key field, even if it is just a composite of the two values. That would have made this question go away.

However, to solve the problem now you need to do a fetch on one key similar to what you have above and then loop over the second key. However, you do not need to do a loop within a loop. You can use a second NSPredicate against that returned array to get the objects to modify.

Less ugly and quite efficient since you are only going to disk once and the second filter is happening in memory.

Update

@DuncanGroenwald is correct that you still must loop through every object, but there is looping and there is looping.

A developer writing a for loop and then doing a string compare inside of that for loop is significantly less efficient then letting the frameworks perform the same option. How? With a NSPredicate against the array:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"someValue IN %@", idArray];
NSArray *results = [origArray filteredArrayWithPredicate:predicate];

If you test both options, the predicate will run significantly faster.



回答2:

Well what I did is to create another attribute named "identifier" which is a stringWithFormat:@"%@%@",key1,key2, it doesn't matter the extra string in coredata because it suppose to have just a few managed objects in that entity