Deletions in a many-to-many structure
Asked Answered
D

3

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?

Diagnostician answered 19/2, 2011 at 5:55 Comment(0)
U
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.

Unbodied answered 19/2, 2011 at 6:44 Comment(2)
Thanks a lot for this! However, how does your approach compare to the answers from here?Diagnostician
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.Unbodied
F
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];
}
Favus answered 18/7, 2012 at 20:30 Comment(3)
just remember to call super !Unbodied
@Favus dope, ARC does not call super automatically.Auger
@Andy Oops, yes, you and regorge were quite correct, for some reason I was thinking about dealloc. Thanks!Favus
W
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)
    }
  }
Withrow answered 14/10, 2015 at 17:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.