Ссылка на броски таблицы соединений ArgumentNullException 'Значение не может быть нулевым' - PullRequest
0 голосов
/ 03 октября 2018

Я пытаюсь получить ингредиенты через таблицу соединений для моих рецептов.

_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();

Я обнаружил, что это вызвано g.Key.RecipeIngredients, но я не могу найти никакого обходного пути, решение для этогопроблема.Я попытался загрузить eagar (как вы можете видеть) и ленивую загрузку, оба не работали.Я надеюсь, что есть решение в одном запросе к БД в linq.Более того, будет ли он работать так же, как в приведенной выше строке, после обновления.

1 Ответ

0 голосов
/ 03 октября 2018

Include не работает, когда вы меняете форму запроса (например, когда вы запрашиваете RecipeIngredient s, но проецируете на другой тип).

Единственное место, где ядумая, что NULL - это проблема, это ключевой селектор при создании словаря.Поскольку Include ничего для вас не сделает, ri.Ingredient всегда будет NULL.Включите Ingredient s в исходную проекцию (и удалите Include, поскольку она бесполезна):

_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 )
    } );

Редактировать: если вам не нужны целые RecipeIngredient или Recipe сущности вваши результаты, просто спроецируйте то, что вам нужно, в имени orig с RecipeIngredient s в первой проекции:

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

Затем используйте эту проекцию для построения вашего словаря:

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