3

I have a CoreData datamodel that includes a many-to-many relationship. As it turns out NSPredicate does not support many-to-many relationships. From CoreData.pdf: "You can only have one to-many element in a keypath in a predicate."

As a Recipe example: Many recipes and many ingredients. A recipe can have many ingredients of which "salt" can be one, while "salt" is used in many recipes. This is a natural many-to-many relationship.

What are suggested work-arounds?
Was CoreData a bad idea and I should go back to SQLite?

Duncan Babbage
  • 19,972
  • 4
  • 56
  • 93
zaph
  • 111,848
  • 21
  • 189
  • 228
  • 1
    "Many recipes have the ingredient "salt" and "salt" is used in many recipes." that's one thing said in two ways. – just somebody Dec 14 '09 at 20:23
  • @just somebody Consider a recipe entity and an ingredient entity. There are many recipes and many have the same ingredients. There are many ingredients that are used in many recipes. That is not the same thing. There is the need to only have one instance of the salt ingredient in the ingredients entity. There is also the need to find all the ingredients in a recipe. It is desirable to find all the recipes that use salt. That is a many-to-many relationship. SUch a relationship is actually created with an intermediate table which CoreData does. – zaph Dec 14 '09 at 20:54
  • I have corrected the question to say "A recipe can have many ingredients..." which was clearly the intended example. – Duncan Babbage Oct 02 '11 at 10:58

2 Answers2

5

My understanding is that you can make any many-to-many relationship into separate one-to-many relationships by adding an intermediate entity.

You have:
Recipe has many Ingredients.
Ingredient has many Recipes.

Create a new RecipeIngredient entity such that:
Recipe has many RecipeIngredients.
Ingredients has many RecipeIngredients.
A RecipeIngredient has one Recipe and one Ingredient.

gerry3
  • 21,420
  • 9
  • 66
  • 74
  • Yes, that is basically what I have decided to do. CoreData creates the intermediate table, just can't use it in a NSPredicate. – zaph Dec 14 '09 at 21:27
  • But if YOU create the intermediate entity, then you CAN use it with an NSPredicate. In general, it is better to create a model that meets your needs and let Core Data handle the details then to worry about how Core Data might be implementing your model in SQLite – gerry3 Dec 14 '09 at 21:32
  • I hesitate to contradict someone with 8,017 reputation, but gerry3... this sounds like a huge kludge and thus terrible advice. I suggest readers see [this thread with different advice](http://stackoverflow.com/questions/1347776/how-to-correctly-setup-a-nspredicate-for-a-to-many-relationship-when-using-core-d) – Duncan Babbage Oct 02 '11 at 11:02
  • @Duncan Babbage In general, explicitly creating an entity for the "join table" is common and can be required. For example, if you wanted to store data on the RecipeIngredients (e.g. how much salt to use). If you have a better answer to this question, please add it and start earning up votes. – gerry3 Nov 04 '11 at 21:08
  • Brilliant - Thank you very much. – Ríomhaire Apr 20 '16 at 14:33
1

This question actually led me down the wrong path with a problem I was having. It turns out you can query a many-to-many relationship with a predicate. You just can't query further down like A <<-->> B <<-->> C

The predicate I used (in a model with Story <<-->> Team) was this...

[NSPredicate predicateWithFormat:@"SUBQUERY( teams, $t, $t IN %@ ).@count > 0", teams)];

This predicate is used in a fetch request against the Story entity. The second "teams" is a set or array of teams I am searching for stories about. The SUBQUERY format is a bit confusing to me, so I'll note it can be read as, "For each team t in the current story's teams collection, see if it is in this other collection (teams)."

Hope this helps.

rob5408
  • 2,972
  • 2
  • 40
  • 53