Joseph Astrahan Joseph Astrahan - 28 days ago 20
iOS Question

How to get a NSBatchDeleteRequest to delete and allow you to add back to an object again

I have the following code.

let workorderFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Workorders")
let deleteWorkOrderRequest = NSBatchDeleteRequest(fetchRequest: workorderFetchRequest) //Deletes ALL workorders

//Question is will it delete all references to the work orders correctly now?
try context.execute(deleteWorkOrderRequest)

//Save the work order objects (overwriting any old ones with same id if needed)
do {
try context.save()
print("Saved context with workorders")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
print("Could not save, unknown error")
}

print("deleted references")


A workorders looks like this...

import Foundation
import CoreData

extension Workorders {

@nonobjc public class func fetchRequest() -> NSFetchRequest<Workorders> {
return NSFetchRequest<Workorders>(entityName: "Workorders");
}

@NSManaged public var address: String?
@NSManaged public var client_id: Int64
@NSManaged public var desc: String?
@NSManaged public var id: Int64
@NSManaged public var phone: String?
@NSManaged public var signaturepath: String?
@NSManaged public var lat: String?
@NSManaged public var lng: String?
@NSManaged public var service: Service?
@NSManaged public var pictures: NSSet?
@NSManaged public var videos: NSSet?

}

// MARK: Generated accessors for pictures
extension Workorders {

@objc(addPicturesObject:)
@NSManaged public func addToPictures(_ value: Pictures)

@objc(removePicturesObject:)
@NSManaged public func removeFromPictures(_ value: Pictures)

@objc(addPictures:)
@NSManaged public func addToPictures(_ values: NSSet)

@objc(removePictures:)
@NSManaged public func removeFromPictures(_ values: NSSet)

}

// MARK: Generated accessors for videos
extension Workorders {

@objc(addVideosObject:)
@NSManaged public func addToVideos(_ value: Videos)

@objc(removeVideosObject:)
@NSManaged public func removeFromVideos(_ value: Videos)

@objc(addVideos:)
@NSManaged public func addToVideos(_ values: NSSet)

@objc(removeVideos:)
@NSManaged public func removeFromVideos(_ values: NSSet)

}


I have it referencing a service object that looks like this...

import Foundation
import CoreData

extension Service {

@nonobjc public class func fetchRequest() -> NSFetchRequest<Service> {
return NSFetchRequest<Service>(entityName: "Service");
}

@NSManaged public var id: Int64
@NSManaged public var name: String?
@NSManaged public var templatedata: String?
@NSManaged public var workorder: Workorders?

}


When I run the delete code I have on the model for workorder it set to Nullify as the delete rule ... (refer to image below)

enter image description here

When I run the batch delete however it does not seem to be nullifying service correctly. When I attempt to set a new service onto the workorder it crashes with...

libc++abi.dylib: terminating with uncaught exception of type NSException

I'm sure this is the case because if I set the delete rule to cascade on the workorders then it fixes the issue. However, I want to keep the old services just nullify the reference.

Why can I not set a new service onto the workorder without it crashing?

Attached below is the area in code it crashes by looking at the console messages I've narrowed it down to the moment I attempt to set service.

enter image description here

Also note, I'm using a NSMergeByPropertyObjectTrumpMergePolicy since I intend to set the same ID service to the workorder again, so when I create a new service with the same ID it should just overwrite the data of the old service if my understanding is correct. Could this be the issue, and if so how do I fix it?

Answer

I find some issues from your trying.

At first, I think you need to revise Entity names. They should be single type.

For example, you used "Workorders" or "Pictures" for them. It should be "Workorder" and "Picture".

And the main issue is that you synced managedObjects before you setup right relationship.

For example, you created one service object and its workorder relationship is nil yet. In this point, you saved context. It could happen if you had optional relationship.

And you created workorder object and bind existing service to its relationship.

Core Data tries to bind new workorder to workorder relationship of service object vise versa.

So it should be done in one transaction. Finally it means you need to save context once after you complete setting up relationship.

So remove saveContext line for service.

Lets say you did it as you did now. After you save context with new service, you created workorder1 with setting service for its relationship. And then the app crashed or has been stopped by something. It causes data integrity issue in those cases.

I hope this will help your understanding about this issue and solved it.

Cheers!