【问题标题】:Reference to junction table throws ArgumentNullException 'Value cannot be null'对联结表的引用引发 ArgumentNullException 'Value cannot be null'
【发布时间】:2018-10-02 22:08:48
【问题描述】:

我正在尝试通过连接表为我的食谱获取成分。

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

【问题讨论】:

    标签: c# entity-framework linq .net-core entity-framework-core


    【解决方案1】:

    Include 在您更改查询形状时不起作用(例如,当您查询 RecipeIngredients 但投影到另一种类型时)。

    我认为 NULL 的唯一问题是创建字典时的键选择器。由于Include 不会为您做任何事情,ri.Ingredient 将始终为 NULL。在原始投影中包含Ingredients(并删除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 )
        } );
    

    编辑:如果您的结果中不需要整个 RecipeIngredientRecipe 实体,只需在第一个投影中使用 RecipeIngredients 在原始名称中投影您需要的内容:

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

    然后使用该投影来构建您的字典:

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

    【讨论】:

    • 这是我第一个想到的抛出异常的地方。我已经编辑了我的问题。
    猜你喜欢
    • 1970-01-01
    • 2022-06-10
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多