Is it possible to perform NSBatchUpdateRequest with an array of NSManagedObjectID?

Viewed 234

Currently, I perform multiple update operations via the following code.

func updateOrders(_ updates : [(objectID: NSManagedObjectID, order: Int64)]) {
    if updates.isEmpty {
        return
    }
    
    let coreDataStack = CoreDataStack.INSTANCE
    let backgroundContext = coreDataStack.backgroundContext

    backgroundContext.perform {
        for update in updates {
            let objectID = update.objectID
            let order = update.order
            let nsPlainNote = try! backgroundContext.existingObject(with: objectID) as! NSPlainNote
            nsPlainNote.order = order
        }
        RepositoryUtils.saveContextIfPossible(backgroundContext)
    }
}

Since I would like to

  • Make the update operations run faster
  • Avoid delegate of NSFetchedResultController from being notified

I would like to utilise NSBatchUpdateRequest for performing such update operation.

However, I don't find a way, how I can apply array of NSManagedObjectID and array of Int64 value, to NSBatchUpdateRequest.

Given an array of NSManagedObjectID and Int64, is it possible to use NSBatchUpdateRequest to perform updated on CoreData?

2 Answers

You must use NSPredicate to set object id

func updateOrders(_ updates : [(objectID: NSManagedObjectID, order: Int64)]) {
    updates.forEach {
        let request = NSBatchUpdateRequest(entityName: "NSPlainNote")
        request.propertiesToUpdate = ["order": $0.order]
        request.predicate = NSPredicate(format: "objectID == %@", $0.objectID)
        let result = try? context.execute(request)
    }
}

NSBatchUpdateRequest is not suitable for your task since using it makes sense for large amount of records with a common attribute's value so that you can filter all by your criteria and update all fields with your values at once.

The fact is that the NSBatchDeleteRequest is an NSPersistentStoreRequest which operates at the SQL level in the persistent store itself and it doesn't update your in-memory objects after execution thats why it works so fast and Core Data translates your native requests to a SQL ones where you can not use dynamically code to get and insert needed data from dictionary etc. but you can update the current value of a filed e.g.:

let batchRequest = NSBatchUpdateRequest(entityName: "Note")
batchRequest.predicate = predicate
// Increase `order` value
batchRequest.propertiesToUpdate = ["order" : NSExpression(format: "order + 1")]
do {
    try context.execute(batchRequest)
}
catch {
    fatalError(error.localizedDescription)
}
Related