Search code examples
ioscore-dataswiftmany-to-manyentity-relationship

CoreData many to many relationship Best practices


give the structure:

Person

  • field1
  • ...
  • fieldn
  • >>itemsTaken(inverse: takenFrom)

Item

  • field1
  • ...
  • fieldn
  • >> takenFrom(inverse: itemsTaken)

Person.itemsTaken <<------>>Items.takenFrom

the scenario is that I have a list of Persons and a list of Items

now I would to show within the Person Detail View the items he taken (this is simply solved), and to show on the Item detail View the complete list of persons and select a subset of person that taken that item.

the problem is the 2nd view where I would to add/remove from the orderedset "takenFrom" a person.

override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
    let mo = self.fetchedResultsController.objectAtIndexPath(indexPath) as NSManagedObject

    if var x: NSMutableOrderedSet = mo.valueForKey("itemsTaken") as? NSMutableOrderedSet {
        x.addObject(detailItem)
        mo.setValue(x, forKey: "itemsTaken")
    }
    if var x: NSMutableOrderedSet = detailItem.valueForKey("takenFrom") as? NSMutableOrderedSet {
        x.addObject(mo)
        detailItem.setValue(x, forKey: "takenFrom")
    }
    (UIApplication.sharedApplication().delegate as AppDelegate).saveContext()
}

override func tableView(tableView: UITableView!, didDeselectRowAtIndexPath indexPath: NSIndexPath!) {
    let mo = self.fetchedResultsController.objectAtIndexPath(indexPath) as NSManagedObject


    if var x: NSMutableOrderedSet = mo.valueForKey("itemsTaken") as? NSMutableOrderedSet {
        x.removeObject(detailItem)
        mo.setValue(x, forKey: "itemsTaken")
    }
    if var x: NSMutableOrderedSet = detailItem.valueForKey("takenFrom") as? NSMutableOrderedSet {
        x.removeObject(mo)
        detailItem.setValue(x, forKey: "takenFrom")
    }

    (UIApplication.sharedApplication().delegate as AppDelegate).saveContext()


}

that works but when I restarted the app all references for relationship are lost but I'm not sure I'm proceeding in the correct way.

before this approach I had 2 more entities in order to have for each entity a one 2 many relationships. I'm looking for a cleaner solution

do you have any suggestion or question?

just a clarification. the target is to add/remove references from person.itemsTaken and/or Item.takenFRom I would to avoid to delete Person. can I remove only the reference within the relationship?


Solution

  • "Cleaner solution": first step would be to make your code more readable. Why call a variable mo or x if the object is better described as a person or as itemsTaken? An additional strategy to make your code more readable is to use NSManagedObject subclasses.

    Second, it seems that you are adding the relationship twice (once for each side). I don't think this is necessary.

    Third, you might want to check if your mutable ordered set is extracted the way you expect. I think it might be advisable to use the mutable accessor instead:

    var itemsTaken = person.mutableSetValueForKey("itemsTaken")
    

    Not sure if you still have to cast or do other things in order to keep the ordering in the ordered set. In my experience, the ordered set never really worked reliably even in Objective-C, so you might just want to keep an additional attribute for the ordering and change the model to use a simple many-to-many relationship.