Reputation: 58963
I know how to use NSPredicate to perform a SQL SELECT
-like operation. How can I perform something like DELETE WHERE
? Do I have to call [NSManagedObjectContext deleteObject]
for each fetched object? Thanks
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:TASK_ENTITY inManagedObjectContext:managedObjectContext]];
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"label LIKE %@", label];
[request setPredicate:predicate];
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
[managedObjectContext deleteObject:[array objectAtIndex:0]];
Upvotes: 19
Views: 6275
Reputation: 388
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:TASK_ENTITY inManagedObjectContext:managedObjectContext];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"label LIKE%@", label.text]];
NSError* error = nil;
NSArray* results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if(![results count]==0)
{
[managedObjectContext deleteObject:[results objectAtIndex:0]];
}
if (![managedObjectContext save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
Upvotes: 0
Reputation: 40018
You can use NSBatchDeleteRequest
available on iOS 9.0+
, macOS 10.11+
, tvOS 9.0+
, watchOS 2.0+
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"label LIKE %@", label];
NSFetchRequest *fetchRequest = [TaskEntity fetchRequest];
[fetchRequest setPredicate:predicate];
// Create batch delete request
NSBatchDeleteRequest *deleteReq = [[NSBatchDeleteRequest alloc] initWithFetchRequest:fetchRequest];
NSError *error = nil;
NSBatchDeleteResult *deletedResult = [appDelegate.persistentContainer.viewContext executeRequest:deleteReq error:&error];
if (error) {
NSLog(@"Unable to delete the data");
}
else {
NSLog(@"%@ deleted", deleteReq.result);
}
Swift code (from the above link)
let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Employee")
fetch.predicate = NSPredicate(format: "terminationDate < %@", NSDate())
let request = NSBatchDeleteRequest(fetchRequest: fetch)
do {
let result = try moc.execute(request)
} catch {
fatalError("Failed to execute request: \(error)")
}
I found below comment about execute
of moc
Method to pass a request to the store without affecting the contents of the managed object context.
Which means any unsaved data in moc
won't be affected. i.e. if you've created/updated entity that falls in the delete request criteria and don't called save
on moc
then that object won't be deleted.
Upvotes: 1
Reputation: 5961
I just tried this and it is successful:
NSError *error = nil;
NSFetchRequest* fetchrequest = [NSFetchRequest fetchRequestWithEntityName:@"EntityName"];
[request setPredicate:[NSPredicate predicateWithFormat:@"attribute == %@", variable]];
NSArray *deleteArray = [context executeFetchRequest:fetchrequest error:&error];
if (deleteArray != nil)
{
for (NSManagedObject* object in deleteArray)
{
[context deleteObject:object];
//Reload/refresh table or whatever view..
}
[context save:&error];
}
Upvotes: 0
Reputation: 428
I believe looping over the returned array and calling [NSManagedObjectContext deleteObject:]
is the "correct"/idiomatic way to do it. It might seem inefficient, but remember that the fetch command doesn't actually fetch the objects' data, and the deleteObject:
method just marks the object for deletion, which gets applied when you send [NSManagedObjectContext save:]
. Not knowing the internals of Core Data I can't tell you whether it's as efficient as a DELETE WHERE
query (presumably Core Data has the indexed primary keys in memory from the fetch, and uses those) but in my experience with profiling Core Data apps it's not significantly slower than saving new or updated objects.
Upvotes: 6
Reputation: 8664
I haven't found an other way than to use an NSArray method for deletion.
(If there is I want to know about it)
You could nest the call to have it on one line if you really don't wan't to store the array. But if you do so verify what is the return of the Fetch in case of an error.
makeObjectsPerformSelector :
Sends to each object in the array the message identified by a given selector, starting with the first object and continuing through the array to the last object.
- (void)makeObjectsPerformSelector:(SEL)aSelector
Or there is a block one to that is suppose to be faster.
Upvotes: 0