tags:

views:

84

answers:

3

Simple IList update question: given the following nested objects, how do you update the deepest nested property given the primary key?

public class Recipe {
    public int RecipeID {get;set;}     // PK

    public string name {get;set;}
    public IList<RecipeStep> RecipeSteps {get;set;}
}

public class RecipeStep {
    public int RecipeID {get;set;}     // PK
    public int RecipeStepID {get;set;} // PK

    public string name {get;set;}
    public IList<Ingredient> {get;set;}
}

public class Ingredient {
    public int RecipeID {get;set;}     // PK
    public int RecipeStepID {get;set;} // PK
    public int IngredientID {get;set;} // PK

    public string name {get;set;}
}

So how could I set the Recipe.RecipeStep.Ingredient.name given that RecipeID = 2, RecipeStepID = 14, and IngredientID = 5 (which are the values of the int, not the index). Hopefully there is some direct way to reference these items without a loop. Linq Expressions are fine. (When I tried Linq, I ended up changing a copy of the value, not the value itself. LOL).

+2  A: 

You're looking for selectmany, it can take multiple depths of ienumerable and flatten them into a unioned resultset in one ienumerable, a selectmany() to get all ingredients, then do a where() for your conditions

Ingredient ing = theRecipe.RecipeSteps.SelectMany((recipeStep) => recipeStep.Ingredient)
    .FirstOrDefault((ingredient) =>
        ingredient.RecipeId == 2 &&
        ingredient.RecipeStepId == 14 &&
        ingredient.IngredientId == 5);

ing.name = "pretty flowers";
Jimmy Hoffa
A: 

Linq query:

Ingredient ing = theRecipe.RecipeSteps.Ingredients
    .FirstOrDefault(i =>
        i.RecipeId == 2 &&
        i.RecipeStepId == 14 &&
        i.IngredientId == 5);

if (ing != null) ing.name = "New Name";
Andreas Rehm
This wont work because ingredients is a list in a list of recipesteps.
Jimmy Hoffa
I've corrected this already... But you're right - your code cares about the many relationship.
Andreas Rehm
+1  A: 
Ingredient theIngredient =
(
  from r in Recipes
  where r.RecipeId == 2
  from rs in r.RecipeSteps
  where rs.RecipeStepID == 14
  from ing in rs.Ingredients
  where ing.IngredientId == 5
  select ing
).Single()

theIngredient.name = theName;
David B
All of these are good answers, but this one is pretty snazzy. I was afraid that it wouldn't return a reference value so that updating theIngredient.name would update the original and not a copy. Worked pretty well. I also like the nested nature of the select statement (from, where, from, where).
Dr. Zim
Thanks. In LinqToObjects - that "from-where" weaving is not just for show - the technique keeps the query from exploring extra receipes and recipesteps.
David B