Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data Deletion rules and many-to-many relationships

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?

like image 522
Felix Lamouroux Avatar asked Oct 23 '09 09:10

Felix Lamouroux


People also ask

What is the function of a deletion rule?

Setting the Delete Rule to Protect prevents deleting records of the main Entity while there are associated records in the related Entity. This behavior is ensured by a database constraint created on the reference attribute.

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.

What is Core Data stack in Swift?

Overview. Core Data provides a set of classes that collaboratively support your app's model layer: An instance of NSManagedObjectModel describes your app's types, including their properties and relationships. An instance of NSManagedObjectContext tracks changes to instances of your app's types.


2 Answers

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];
like image 119
Alex Avatar answered Oct 11 '22 16:10

Alex


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.

like image 33
Felix Lamouroux Avatar answered Oct 11 '22 17:10

Felix Lamouroux