简体   繁体   中英

Reference to junction table throws ArgumentNullException 'Value cannot be null'

I'm trying to get Ingredients through junction table for my Recipes.

_context.RecipeIngredients
    .Include(rI => rI.Recipe)
        .ThenInclude(r => r.RecipeIngredients)
    .Where(rI => ingredients.Contains(rI.IngredientId))
    .GroupBy(rI => rI.Recipe)
    .Select(g => new
    {
        Recipe = g.Key,
        MatchingIngredients = (double)g.Count() / (double)g.Key.RecipeIngredients.Count(),
        g.Key.ComplexityTag,
        g.Key.TypeTag,
        g.Key.RecipeIngredients,
    })
    .OrderByDescending(r => r.MatchingIngredients)
    .Take(MaxAmountBestRecipes)
    .AsEnumerable()
    .Select(a => new RecipeDTO()
    {
        Title = a.Recipe.Title,
        Steps = a.Recipe.Steps,
        ComplexityTag = a.ComplexityTag?.Complexity,
        TypeTag = a.TypeTag?.Type,
        IngredientAmount = a.RecipeIngredients?.ToDictionary(rI => rI.Ingredient.Name, rI => rI.Quantity),
    })
    .ToList();

I discovered it is caused by g.Key.RecipeIngredients, but I can't find any workaround, solution for this problem. I tried eagar loading(as you can see), and lazy loading, both didn't work. I hope there is solution in one query to db in linq. Moreover, will it work like in the above line, after update.:

IngredientAmount = a.RecipeIngredients?.ToDictionary(rI => rI.Ingredient.Name, rI => rI.Quantity)

EDIT I have divied linq query and here you have after which statement ArgumentNullException is thrown:

var tmp = _context.RecipeIngredients
            .Where(rI => ingredients.Contains(rI.IngredientId))
            .GroupBy(rI => rI.Recipe)
            .Select(g => new
            {
                Recipe = g.Key,
                MatchingIngredients = (double)g.Count() / (double)g.Key.RecipeIngredients.Count(),
                g.Key.ComplexityTag,
                g.Key.TypeTag,
                g.Key.RecipeIngredients
            })
            .ToList();

Include doesn't work when you change the shape of the query (eg when you're querying for RecipeIngredient s but are projecting to another type).

The only place I'm thinking a NULL is a problem is the key selector when creating the dictionary. Since Include won't do anything for you, ri.Ingredient will always be NULL. Include the Ingredient s in the original projection (and remove the Include since it's useless):

_context.RecipeIngredients
    .Where( rI => ingredients.Contains( rI.IngredientId ) )
    .GroupBy( rI => rI.Recipe )
    .Select( g => new
    {
        Recipe = g.Key,
        MatchingIngredientCount = (double)g.Count() / (double)g.Key.RecipeIngredients.Count(),
        g.Key.ComplexityTag,
        g.Key.TypeTag,
        g.Key.RecipeIngredients,
        // this eager-loads the `Ingredient` entities
        //   EF will automatically wire them up to the `RecipeIngredient` entities
        //   if tracking is enabled
        Ingredients = g.Key.RecipeIngredients.Select( ri => ri.Ingredient ),
    } )
    .OrderByDescending(r => r.MatchingIngredients)
    .Take(MaxAmountBestRecipes)
    .ToArray()
    .Select( a = new ...
    {
        ...
        IngredientAmount = a.RecipeIngredients.ToDictionary(
            ri => ri.Ingredient.Name, // ri.Ingredient should now not be NULL
            ri => ri.Quantity )
    } );

Edit: if you don't need the entire RecipeIngredient or Recipe entities in your results, just project what you need in the orig name with the RecipeIngredient s in the first projection:

IngredientNamesAndQuantity = g.Key.RecipeIngredients.Select( ri => new
{
    ri.Quantity,
    ri.Ingredient.Name,
}

Then use that projection to build your dictionary:

IngredientAmount = a.IngredientNamesAndQuantity.ToDictionary(
    at => at.Name,
    at => at.Quantity )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM