Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data delete rule -- to-many relationship, delete when empty

I'm a little fuzzy on how the delete rules for relationships in Core Data work, at least beyond the simple cases described in the documentation.

Most of those cases, and most of the answers I've seen for questions here, use a model where the object on left side of a one-to-many relationship "owns" the objects on the right side: e.g. a Person has PhoneNumbers, and if you delete the person you delete all their associated numbers. In that kind of case, the solution is clear: Core Data will handle everything for you if you set the relationships like so:

Person      --(cascade)-->> PhoneNumber
PhoneNumber --(nullify)-->  Person

What I'm interested in is the opposite: A to-many relationship where the "ownership" is reversed. For example, I might extend the CoreDataBooks sample code to add an Author entity for collecting all info about a unique author in one place. A Book has one author, but an author has many books... but we don't care about authors for whom we don't list books. Thus, deleting an Author whose books relationship is non-empty should not be allowed, and deleting the last Book referencing a particular Author should delete that Author.

I can imagine a couple of ways to do this manually... what I'm not sure of is:

  • does Core Data have a way to do at least some of this automagically, as with relationship delete rules?
  • is there a "canonical", preferred way to handle this kind of situation?
like image 650
rickster Avatar asked Mar 14 '12 18:03

rickster


People also ask

How do I clear my 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 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.


3 Answers

The following worked for me:

Set the deletion rule on the 'book' relationship of your author entity to 'Deny' meaning that as long as there is a book linked to your author it cannot be deleted.

Subclass your book entity and override the prepareForDeletion() function as follows:

public override func prepareForDeletion() {
    super.prepareForDeletion()
    do {
        try author.validateForDelete()
        managedObjectContext?.delete(author)
    } catch {}
}

Validate for delete will throw an error unless the book relationship is empty. You can optionally handle the error.

like image 182
Azure Avatar answered Sep 30 '22 12:09

Azure


You could override prepareForDeletion in your Book class and check if the author has any other books. If not you could delete the author.

- (void)prepareForDeletion {
    Author *author = self.author;
    if (author.books.count == 1) { // only the book itself
        [self.managedObjectContext deleteObject:author];
    }
}

Edit: To prevent deletion of an author with books you could override validateForDelete or even better: don't call deleteObject with an author with books in the first place

like image 15
tim Avatar answered Oct 13 '22 18:10

tim


Rickstr,

Check below for the relationships to get your two criteria done.

  1. Author -- (Deny) -->> Books

deleting an Author whose books relationship is non-empty should not be allowed

DENY: If there is at least one object at the relationship destination, then the source object cannot be deleted.

  1. Book -- (Cascade)-- > Author

deleting the last Book referencing a particular Author should delete that Author

You cannot delete the Author, as our first rule is saying, if there are any Books which are non-empty should not be deleted. If they are not present the Author gets deleted.

I think theoretically it should work. Let me know, if this works or not.

like image 2
Jay Avatar answered Oct 13 '22 20:10

Jay