Akaino Akaino - 2 years ago 84
Swift Question

Core Data many to many relation with intermediate table (Swift 2)

TL;DR EDIT with answer

As Wain perfectly answered this is how I get my information now:

let ingredientsToRecipe = recipe.valueForKey("ingredientsToRecipe")! as! NSSet
for i in ingredientsToRecipe {
print(i.valueForKey("amount")!)
print(i.valueForKeyPath("ingredient.name")!)
}


Original question

I have a huge problem understanding the usage of intermediate tables in CoreData. I've searched SO for answers and found a few threads about intermediate tables and many-to-many relations but those where either Objective-C or didn't help me.

I have the following setup (simplified):
image

Now I want to add a new recipe with a bunch of ingredients.
Let's say a Burger. The burger consists of


  • 1 cocumber,

  • 1 Tomato,

  • 1 Meat,

  • 2 bread

    (yummy...)



This is what I tried so far:

// Core Data
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let entity = NSEntityDescription.entityForName("Recipe",
inManagedObjectContext:managedContext)
// creating a new recipe with name and id
let recipe = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext: managedContext)
recipe.setValue("Burger", forKey: "name")
recipe.setValue("B_001", forKey: "id")


Now I got an
Array:[NSManagedObject]
of of ingredients (created just like the Burger) and a
Dictionary
of amounts to the ingredient_IDs. This is how I'm trying to marry my Recipe with the ingredients (over the intermediate table).

for i in selectedIngredients { // the ingredient array
let ingredientsToRecipe = NSEntityDescription.insertNewObjectForEntityForName("RecipeIngredient", inManagedObjectContext: managedContext)

ingredientsToRecipe.setValue(i, forKey: "ingredient")
ingredientsToRecipe.setValue(recipe, forKey: "recipe")

let quantity = Double(quantityDictionary[(i.valueForKey("id") as! String)]!) // the amount-to-ID dictionary
ingredientsToRecipe.setValue("\(quantity)", forKey: "quantity")
}


In the end I simply save everything:

do {
try managedContext.save()
print("Saved successfully")
self.dismissViewControllerAnimated(true, completion: nil)
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}


All this above somehow works. But now I'm struggling to fetch information about my recipes.
How am I supposed to fetch the amount of tomatoes of this specific burger?

Things like
recipe.valueForKey("RecipeIngredient").valueForKey("amount")
work but I don't know which amount is from which ingredient.
Am I doing anything wrong?
What can/should I do better?

The goal is to create a recipe with ingredients and later populate a Table with information about the recipe and the amounts of it's ingredients (and the ingredients themselves).

I appreciate any help!

Answer Source

The power of the intermediate object is that it takes your many-to-many relationship and breaks it into multiple one-to-many relationships. The to-one relationships are easy to navigate.

So, from your Recipe you can get an array of RecipeIngredients, and for each one you can get valueForKey("amount") and valueForKeyPath("ingredient.name").

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download