21

I just want to check really quickly. Say I have two entities in a data model: Catalog, and Product. They have a many-to-many relationship with each other, and both are required (a Catalog must have at least one Product, and all Products must each belong to at least one Catalog). So if I was to delete a Product, its deletion should be Nullify, of course.

But what should the deletion policy be for Catalog? If a Catalog is deleted, not all of its Products necessarily exclusively belong to it. A Product may belong to more than one Catalog. So I definitely shouldn't use Cascade. However, is Nullify sufficient? What if I end up with dangling Products that don't belong to a Catalog? What does Core Data have built in that would resolve this issue with many-to-many schemas? Do I need to modify my schema?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Apophenia Overload
  • 2,485
  • 3
  • 28
  • 46

3 Answers3

23

Nullify is sufficient, and many-to-many sounds right. The specific constraint you want (deleting orphans) is not directly enforceable by core data, though, so you get to do a little cleanup yourself.

Specifically, implement willSave in your entity classes, and have each entity test: am I not deleted; and, do I have no associated (products/catalogs)? If so, delete myself. (the not-deleted test is important to avoid an infinite loop of willSaves.)

This postpones the deletion of the orphaned catalogs or products until save time. This is probably not a problem.

rgeorge
  • 7,385
  • 2
  • 31
  • 41
  • Thanks a lot for this! However, how does your approach compare to the answers from [here](http://stackoverflow.com/questions/1612356/core-data-deletion-rules-and-many-to-many-relationships)? – Apophenia Overload Feb 19 '11 at 08:59
  • They work too; there's more than one way to do it. The first method is more code when deleting a Department, in exchange for orphans Employees being deleted immediately instead of at save time. My design instinct would rather put responsibility for orphan cleanup in the class of the orphan entity itself. If deletion needs to happen immediately instead of at save, a KVO observation could trigger cleanup instead, though kvo can be tricky to get right. I wouldn't recommend the notification method; that runs your cleanup code whenever any change at all happens in the context. – rgeorge Feb 19 '11 at 18:24
13

I've implemented rgeorge's answer, and thought the exact code might be helpful to other people:

- (void)willSave
{
    [super willSave];

    if (self.isDeleted)
        return;

    if (self.products.count == 0)
        [self.managedObjectContext deleteObject:self];
}
pronebird
  • 12,068
  • 5
  • 54
  • 82
JosephH
  • 37,173
  • 19
  • 130
  • 154
1

Swift translation of Andy and JosephH

override func willSave() {
    super.willSave()

    if self.deleted {
      return
    }

    if self.products.count == 0 {
      self.managedObjectContext?.deleteObject(self)
    }
  }
Marco Pappalardo
  • 935
  • 6
  • 23