代码之家  ›  专栏  ›  技术社区  ›  Kacper

对连接表的引用引发ArgumentNullException“值不能为null”

  •  0
  • Kacper  · 技术社区  · 7 年前

    我正试着通过连接表为我的食谱找到配料。

    _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引起的。收到的消息,但我找不到解决这个问题的方法。我尝试了eagar加载(如您所见)和惰性加载,但都不起作用。我希望在linq中对db的一次查询中能找到解决方案。此外,在更新后,它是否会像上面这行一样工作:

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

    编辑 我已经划分了linq查询,下面是在哪个语句之后抛出ArgumentNullException:

    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();
    
    1 回复  |  直到 7 年前
        1
  •  0
  •   Moho    7 年前

    Include 当您更改查询的形状时(例如,当您查询 RecipeIngredient 但它们正投射到另一种类型)。

    我认为空值唯一的问题是创建字典时的键选择器。自从 包括 不会为你做任何事, ri.Ingredient 将始终为空。包括 Ingredient s在原始投影中(并移除 包括 既然没用):

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

    编辑:如果你不需要整个 接受方 Recipe 在结果中的实体,只需使用 接受方 在第一个投影中:

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

    然后使用该投影构建词典:

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