views:

365

answers:

4
+2  A: 

In your domain model create a RecipeIngredient class containing a reference to a specific Ingredient and a Quantity.

Then change the Recipe.Ingredients list to contain RecipeIngredient objects. Finally remove Quantity from the Ingredient class.

Just a tip: most purist domain modellers would say you should create your domain model first and not concern yourself with the database until much later.

Ash
Purists would also say the domain model usually contains some form of behavior :-)
Bryan Watts
I'd suggest renaming RecipeIngredient to "MeasuredIngredient" or "IngredientMeasurement" - something that describes the nature of the entity/value object.
Vijay Patel
A: 

Since you have data in your join table (quantity), the answer is that you need a class to represent it. (There are other alternatives, but not worth considering.)

As your model grows, you will undoubtedly need to add more data here. For example, how do you set the order of the ingredients in the recipe?

RecipeIngredient is a bit of an awkward name (and concept), from a domain driven design perspective. You may be able to come up with different names that feels better. But in general, this is a necessary implementation detail. Sorry, I don't have the Evan's DDD book handy to provide a reference.

ndp
+2  A: 

If you are trying to do domain-driven design don't start with tables. Elaborate first a conceptual model that reflects your underlying domain. I agree with ndp: RecipeIngredient is a bit of an awkward name/concept, from a DDD perspective.

I think the model needs the following concepts: Recipe, Ingredient, Measure and RecipePreparation.

A Recipe is an aggregation of Ingredients. Each Ingredient belonging to a Recipe need a Measure associated to it, as a specification for the preparation. Also you need to model the RecipePreparation to associate the actual quantity of each ingredient used during a specific preparation of the recipe.

A Measure consists of unit and amount (e.g. 2 cups, 0.5 oz, 250 gr, 2 tbsp...).

I see here two different things that could be mixed during analysis and should be kept split: Recipe/Ingredient/Measure as a specification in order to cook something (one instance for each recipe) and RecipePreparation/Ingredient/Measure as a concrete preparation of one recipe, done by a specific person on a specific moment, and may be using different measures (doubled all the ingredients because the recipe specification is for two plates and you have four guests... something like that).

You can go deeper and start modeling things like some ingredients having a set of exchangeable ingredients (e.g. if you don't have goat's cheese use mozzarella), a cookbook that collect a set of recipes of the same category, a cooking time for the recipe, etc.

JuanZe
I agree that having a RecipeIngredient is awkward in the Domain Model and basically ends up as a 1:1 mapping of the database.
Alex Jeffery
A: 

I think you guys are all lost. The original poster had the right impulse, but was taking the wrong route. Actually, the mapping table he shows, using the old Riehl heuristic (combining the names of the l and r relations) seems to be addressing the fact that it's a many-to-many mapping. But what is really happening is that you need a role class here (Coad's Domain Modeling approach used these a lot). Here's the thing though: that's what Ingredient is already! The missing abstraction here opens a can of worms though: it's the thing that's being added. One could argue that that would be a base class, e.g. Food (since we literally, by definition cannot add inedible things to a recipe), but then you have the burden of accounting for all foods, or you can just name them.

So the correct model I think is Recipe contains Ingredients which have some amount of a specific Food.

Rob