Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to delete all objects through a core data relationship?

Say I have a custom NSManagedObject Department and this has a property representing a to-many relationship to employees i.e. NSSet *employees;.

For a given Department, I want to remove all objects in employees. What is the recommended/best way to do this, please?

So, hypothetically, my code would look like this:

Department.h

@interface Department: NSManagedObject { } @property (retain) NSString *departmentName; @property (retain) NSSet *employees; @end 

Department.m

@implementation Department @dynamic departmentName; @dynamic employees; 

Employee.h

@interface Employee: NSManagedObject { } @property (retain) NSString *firstName; @property (retain) NSString *lastName; @property (retain) Department *worksIn; @end 

doCoreDataStuff

- (void)doCoreDataStuff:sender {     //add a department, give it a couple employees, then try to remove those employees     NSEntityDescription *deptEntity = [NSEntityDescription entityForName:@"Department"                                                  inManagedObjectContext:self.managedObjectContext];     Department *dept = [Department alloc] initWithEntity:deptEntity                           insertIntoManagedObjectContext:self.managedObjectContext];     NSError *error;      dept.departmentName = @"Accounting";     //save more often than normal to see more easily what causes error     if (![self.managedObjectContext save:&error]) NSLog(@"\nError: %@", [error localizedDescription]);      NSEntityDescription *empEntity = [NSEntityDescription entityForName:@"Employee"                                                  inManagedObjectContext:self.managedObjectContext];     emp.firstName = @"Steve";     emp.lastName = @"Smith";     emp.worksIn = dept;      if (![self.managedObjectContext save:&error]) NSLog(@"\nError: %@", [error localizedDescription]);      emp = [[Employee alloc] initWithEntity:empEntity             insertIntoManagedObjectContext:self.managedObjectContext];     emp.firstName = @"Natasha";     emp.lastName = @"Johnson";     emp.worksIn = dept;      if (![self.managedObjectContext save:&error]) NSLog(@"\nError: %@", [error localizedDescription]);      //all good so far! now will try to delete all employees for this department     dept.employees = [NSSet set];     if (![self.managedObjectContext save:&error]) NSLog(@"\nError: %@", [error localizedDescription]); //"Multiple validation errors occurred."      //this also produces the same error     [[dept mutableSetValueForKey:@"employees"] removeAllObjects];     if (![self.managedObjectContext save:&error]) NSLog(@"\nError: %@", [error localizedDescription]); //"Multiple validation errors occurred." 

The relationship employees is not optional so I'm guessing that removing employees from the department means that I am trying to "orphan" the employees i.e. keep employees in the persisted model without an associated department.

So, I think my original question should be reworded to: what is best/recommended way to remove all "child" objects of a "parent" when the children have a non-optional relationship with the parent?

I suspect that the answer is going to be "loop through and delete the employee objects one at a time".

UPDATE

According to an answer and a link to Apple's documentation, I should be able to set the delete rule to "Cascade" and then code like department.employees = [NSSet set]; will work. However, this does not work in my very simple project where I have set the delete rule accordingly.

Thanks

like image 536
stifin Avatar asked Jun 11 '11 21:06

stifin


People also ask

How do I delete everything from my Core Data?

Delete Everything (Delete All Objects, Reset Core Data) One approach to delete everything and reset Core Data is to destroy the persistent store. Deleting and re-creating the persistent store will delete all objects in Core Data.

What is NSManagedObject in Core Data?

In some respects, an NSManagedObject acts like a dictionary—it's a generic container object that provides efficient storage for the properties defined by its associated NSEntityDescription instance.

What are relationships in Core Data?

Inverse relationships enable Core Data to propagate change in both directions when an instance of either the source or destination type changes. Every relationship must have an inverse. When creating relationships in the Graph editor, you add inverse relationships between entities in a single step.

How does Core Data save data?

Most interactions with Core Data will occur through an instance of NSManagedObjectContext : the portal through which our app will create new entities, save changes, and fetch from the store. The persistent container comes with a NSManagedObjectContext as one of its built-in properties.


2 Answers

If you want to delete the employee elements for a specific department, then you could run a for-in loop like for

for (Employees * theEmployee in department.employees) {   [self.managedObjectContext deleteObject:[self.managedObjectContext objectWithID:theEmployee.objectID]];  } 

Then save your managed context. IF of course that's what you want, and not remove the relationship between employees and departement; in that case, assigning an empty set would work.

Variation on above:

for (Employee *employeeToDelete in department.employees) {     [self.managedObjectContext deleteObject:employeeToDelete]; } 
like image 159
Remy Vanherweghem Avatar answered Sep 23 '22 01:09

Remy Vanherweghem


Setting the department's employee relationship to an empty set WILL NOT delete the employees, regardless of the deletion rule. I believe you are misunderstanding the deletion rule. According the apple docs: "A relationship's delete rule specifies what should happen if an attempt is made to delete the source object". Thus, cascading will only take effect if we DELETE the department. By setting the relationship to an empty set, all we are doing is separating the employees from the department, not deleting them. And if that relationship is not set to optional for the employees, this will cause an error when saving. If you want to delete the employees from the department, you can iterate through them as listed above, or set the department relationship to cascade and then delete the department.

like image 24
Scott Pfeil Avatar answered Sep 22 '22 01:09

Scott Pfeil