Core Data Deletion rules and many-to-many relationships
Asked Answered
B

2

11

Say you have departments and employees and each department has several employees, but each employee can also be part of several departments.

So there is a many-to-many relationship between employees and departments. When deleting a department I would like to delete all employees that are only part of that department and nullify the relationship to this department for all employees that are also member of another department.

Would a cascade-rule in both directions do that? Or does a cascade rule automatically delete all employees of a department regardless of other affiliations?

Bailsman answered 23/10, 2009 at 9:35 Comment(0)
L
21

A cascade rule will automatically delete the objects at the destination. So, if you delete a department, the employees will be deleted regardless of the number of departments they're in.

It sounds like the behavior you want is a little more nuanced, to delete only the "orphaned" employees -- i.e. those that don't have a department. When you delete a department, a good way of finding those would be to do something like this:

NSManagedObject *doomedDepartment = // get the department to be deleted

NSSet *employees = [doomedDepartment valueForKey:@"employees"];
NSSet *orphanedEmployees = [employees filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"departments.@count == 1"]];
for (NSManagedObject *orphanedEmployee in orphanedEmployees) {
    [managedObjectContext deleteObject:orphanedEmployee];
}    

[managedObjectContext deleteObject:doomedDepartment];
Lyonnais answered 23/10, 2009 at 14:14 Comment(0)
B
5

Thanks, alex. I will probably do that. In the meantime I had found a different way of doing this:

1.) register for notifications on changes:

    [[NSNotificationCenter defaultCenter] addObserver:self 
            selector:@selector(managedObjectContextDidChange:) 
            name:NSManagedObjectContextObjectsDidChangeNotification 
            object:managedObjectContext];

2.) when changes occur and an employee gets updated. I check if that object has 0 relations to departments and delete it:

- (void)managedObjectContextDidChange:(NSNotification *)notification {
    NSSet *updatedObjects = [[notification userInfo] objectForKey:NSUpdatedObjectsKey];

for(NSManagedObject *obj in updatedObjects){        
    // walk through updated objects -> check for employees
    // check if they still contain departments and if not delete them
    if([obj.entity.name isEqualToString:@"Employee"]){
        NSLog(@"Employee changed!");
        if([[(Employee*)obj Departments] count]==0){
            NSLog(@"No more relations -> Delete Employee");
            [managedObjectContext deleteObject:obj];
        }
    }
}}

That works well too, but might get more complicated if you have several different entities for which to observe this kind of behavior.

Bailsman answered 26/10, 2009 at 12:35 Comment(3)
If you are working on Cocoa Touch or Snow Leopard, you can put this logic in the department's -prepareForDeletion method.Lear
When you say department, do you mean an NSManagedObject call department?Heliotropin
In this example the entities in the Model and there NSManagedObject classes are named the same. There are two of them: Employee and Department.Bailsman

© 2022 - 2024 — McMap. All rights reserved.