1

My data model contains two entities: Author and Book with a one to many relationship (one author may write several books).

Let's say that there are only two books and two authors in DB as follows:

  • Book A is assigned to Author X
  • Book B is assigned to Author Y

Assuming following change is applied:

  • Book B is assigned to a new Author Z.

Result:

  • Author Y exists in DB but points to no book.

My question: is it possible to configure the data model so objects like Author Y will be automatically deleted when they are not referenced by any book?

Joshua
  • 1,974
  • 2
  • 23
  • 39
  • Is your data persisted somewhere? If so, is the question about how to delete the objects automatically from the backstore, or how to free up memory? – Russell Zahniser Feb 12 '12 at 13:23
  • Data is persisted in SQLLite and I wish to delete these objects automatically from the backstore. – Joshua Feb 12 '12 at 14:09
  • Did you try setting the delete propagation rule to `cascade`? See this question: http://stackoverflow.com/questions/2124022/how-to-properly-cascade-delete-managed-objects-in-core-data. – Costique Feb 12 '12 at 19:24
  • The Book object is not deleted, it is just assigned to a different Author. In such case the delete rule will not be triggered. It looks like I will have to handle this manually at the time of the assignment. – Joshua Feb 13 '12 at 12:36

2 Answers2

2

Check out "delete propagation". It's there to solve exactly that problem.

If that doesn't do exactly what you want / need: You can override - (void)prepareForDeletion on the Book entity and at that point check for any Authors that are registered with the context and have pending changes (since their inverse will have changed) and have no books:

{
    // ...
    [[NSNotificationCenter defaultNotificationCenter] addObserver:self selector:@selector(deleteOrphanedAuthors:) name:NSManagedObjectContext object:moc];
    // ...
}

- (void)deleteOrphanedAuthors:(NSNotification *)note;
{
    NSManagedObjectContext *moc = [note object];
    NSManagedObjectModel *mom = [[moc persistentStoreCoordinator] managedObjectModel];
    NSEntityDescription *authorEntity = [[mom entitiesByName] objectForKey:@"Author"];
    for (NSManagedObject *author in [moc updatedObjects]) {
        if ([author entity] == authorEntity) {
            if (![author hasFaultForRelationshipNamed:@"books"] && ([[author books] count] == 0)) {
                [moc deleteObject:author];
            }
        }
    }
}

Note: You can not pass nil as the object (i.e. context) to observe, since frameworks you use, might have their own context, and you do not want to mess with them.

Also, note how this code is careful not to touch the author object if it's a fault. If a book is deleted, Core Data will change the corresponding author objects' inverse relationships, hence fault in that relationship, such that it is no longer a fault. And the code will only operate on those objects.

Daniel Eggert
  • 6,665
  • 2
  • 25
  • 41
  • Thanks for the detailed response. I think that the prepareForDeletion will not be called as no object is being deleted. My scenario is assigning a book to a different author so there is no reason that delete rules will take over. – Joshua Feb 13 '12 at 12:37
  • Oh, I missed that part. You can do something similar though. Register for NSManagedObjectContextObjectsDidChange and do the same thing there. I've updated the response. – Daniel Eggert Feb 13 '12 at 17:28
  • One last question.. when having several books with the same author, how can I tell Core Data to delete this author only when the last book (of this author) is deleted? Is the above code handles this case as well? – Joshua Feb 13 '12 at 22:25
  • Yes, that's what `([[author books] count] == 0)` is for. – Daniel Eggert Feb 15 '12 at 07:45
1

You will need to determine "orphaned" books manually.

When you update the Author relationship you could check the old Author's books relationship to see if it still has any books.

Alternatively you could use notifications to determine when the NSManagedObjectContext changes: NSManagedObjectContextObjectsDidChangeNotification. If you register for this notification you can check for a number of changes to Author objects. Have a look at that specific notification in the docs.

Maurice Kelly
  • 1,462
  • 12
  • 15
  • Thanks a lot. I guess that relationship integrity is enforced automatically only via delete rules. I will handle this manually as you suggest. – Joshua Feb 13 '12 at 12:40