I have a Person
entity which has Contacts
to-many relationship to an entity name Contact
.
CoreData creates a NSSet
property for me:
@property (nullable, nonatomic, retain) NSSet<Contact *> *contact_list;
What if I need to completely change the person's contact list? Can I just replace the whole set:
person.contact_list = newContactList
Or should I actually always use CoreData-generated accessors and mutators? e.g.:
person.removeContact_list(person.contact_list) // removing all the current contacts
person.addContact_list(newContactList) // setting a new contact list
Could the former approach cause database errors in the relationship configuration? What is preferred way to completely replace a to-many relationship set?
I assume the core data model is like this:
Question 1: Can I just replace the whole set: person.contact_list = newContactList or should I actually always use CoreData-generated accessors and mutators?
Answer: If all data objects are formerly saved in the database, Core Data creates the same SQL update code (i'm using Swift here but with ObjC it is only syntax differences):
Prepare some objects and save it:
// Create Persons
let personObjA: Person = Person(context: mainContext)
personObjA.name = "Person A"
let personObjB: Person = Person(context: mainContext)
personObjB.name = "Person B"
saveContext()
// Create Contacts
let contactObj1: Contact = Contact(context: mainContext)
contactObj1.name = "Contact A"
let contactObj2: Contact = Contact(context: mainContext)
contactObj2.name = "Contact B"
let contactObj3: Contact = Contact(context: mainContext)
contactObj2.name = "Contact C"
let contactObj4: Contact = Contact(context: mainContext)
contactObj2.name = "Contact D"
saveContext()
Method by assign to a new contact list:
// Set Contacts for PersonA
personObjA.addToContacts([contactObj1,contactObj2])
saveContext()
// Replace Contacts for PersonA
personObjA.contacts = [contactObj3,contactObj4]
saveContext()
Core Data executes this SQL:
CoreData: sql: BEGIN EXCLUSIVE
CoreData: sql: UPDATE OR FAIL ZPERSON SET Z_OPT = ? WHERE Z_PK = ? AND Z_OPT = ?
CoreData: details: SQLite bind[0] = (int64)3
CoreData: details: SQLite bind[1] = (int64)1
CoreData: details: SQLite bind[2] = (int64)2
CoreData: sql: UPDATE OR FAIL ZCONTACT SET Z2CONTACTS = ?, Z_OPT = ? WHERE Z_PK = ? AND Z_OPT = ?
CoreData: details: SQLite bind[0] = (int64)1
CoreData: details: SQLite bind[1] = (int64)2
CoreData: details: SQLite bind[2] = (int64)2
CoreData: details: SQLite bind[3] = (int64)1
CoreData: sql: UPDATE OR FAIL ZCONTACT SET Z2CONTACTS = ?, Z_OPT = ? WHERE Z_PK = ? AND Z_OPT = ?
CoreData: details: SQLite bind[0] = (int64)1
CoreData: details: SQLite bind[1] = (int64)2
CoreData: details: SQLite bind[2] = (int64)3
CoreData: details: SQLite bind[3] = (int64)1
CoreData: sql: COMMIT
Method by using Core Data accessors and mutators:
// Set Contacts for PersonB
personObjB.addToContacts([contactObj1,contactObj2])
saveContext()
// Replace Contacts for PersonB
personObjB.removeFromContacts([contactObj1,contactObj2])
personObjB.addToContacts([contactObj3,contactObj4])
saveContext()
Core Data will execute SQL like this:
CoreData: sql: BEGIN EXCLUSIVE
CoreData: sql: UPDATE OR FAIL ZPERSON SET Z_OPT = ? WHERE Z_PK = ? AND Z_OPT = ?
CoreData: details: SQLite bind[0] = (int64)3
CoreData: details: SQLite bind[1] = (int64)2
CoreData: details: SQLite bind[2] = (int64)2
CoreData: sql: UPDATE OR FAIL ZCONTACT SET Z2CONTACTS = ?, Z_OPT = ? WHERE Z_PK = ? AND Z_OPT = ?
CoreData: details: SQLite bind[0] = (int64)2
CoreData: details: SQLite bind[1] = (int64)3
CoreData: details: SQLite bind[2] = (int64)2
CoreData: details: SQLite bind[3] = (int64)2
CoreData: sql: UPDATE OR FAIL ZCONTACT SET Z2CONTACTS = ?, Z_OPT = ? WHERE Z_PK = ? AND Z_OPT = ?
CoreData: details: SQLite bind[0] = (int64)2
CoreData: details: SQLite bind[1] = (int64)3
CoreData: details: SQLite bind[2] = (int64)3
CoreData: details: SQLite bind[3] = (int64)2
CoreData: sql: COMMIT
Question 2: Could the former approach cause database errors in the relationship configuration?
Answer: If there are simple updates all done in same thread, same context (...) as described in former answer to Question 1 there will no errors in relationship.
Question 3: What is preferred way to completely replace a to-many relationship set?
Answer: If there are simple update steps all done in same thread, same context (...) as described in former answer to Question 1 both is good.