简体   繁体   中英

Core Data: DELETE WHERE

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]];

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.

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)")
}

NOTE:

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. ie 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.

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]);
}

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];
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM