You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core 多对多关系新增关联数据时触发空引用异常求助

问题排查结论

你触发System.NullReferenceException的核心原因和实体关联绑定逻辑无关,是两个基础写法问题:

  • Recipe、Ingredient类中的集合导航属性没有做初始化,默认值为null,直接调用.Add()方法必然触发空引用
  • EF Core的Find()方法默认不会自动加载关联导航属性,就算你给集合做了初始化,查询返回的Recipe实体里RecipeIngredients也不会自动填充关联数据,依然是null
  • 附带一个编译级错误:你Main方法里给RecipeIngredient赋值了Measurement = Measurement.kg,但贴出的RecipeIngredient实体类里没有定义这个属性,项目编译阶段就会报错
修复步骤

1. 初始化所有集合导航属性

修改三个实体类的定义,给集合属性默认赋值空列表,从根源避免null问题:

public class Recipe
{
    public int RecipeId { get; set; }
    public string Name { get; set; }

    public List<RecipeIngredient> RecipeIngredients { get; set; } = new List<RecipeIngredient>();
    public ICollection<Ingredient> Ingredient { get; set; } = new List<Ingredient>();
}

public class Ingredient
{
    public int IngredientId { get; set; }
    public string Name { get; set; }

    public List<RecipeIngredient> RecipeIngredients { get; set; } = new List<RecipeIngredient>();
    public ICollection<Recipe> Recipe { get; set; } = new List<Recipe>();
}

public class RecipeIngredient
{
    public int IngredientId { get; set; }
    public Ingredient Ingredient { get; set; }
    public int RecipeId { get; set; }
    public Recipe Recipe { get; set; }
    public int Quantity { get; set; }
    // 补上你代码里用到的计量单位属性
    public Measurement Measurement { get; set; }
}

记得补上Measurement枚举定义:

public enum Measurement
{
    kg,
    g,
    piece
    // 可自行扩展其他计量单位
}

2. 查询时显式加载需要的导航属性

EF Core不会自动加载关联数据,查询时要通过Include方法指定要加载的关联属性。首先引入EF Core命名空间:

using Microsoft.EntityFrameworkCore;

然后修改Repository层的GetRecipe方法:

public Recipe GetRecipe(int recipeId)
{
    return context.Recipes
        .Include(r => r.RecipeIngredients)
        .ThenInclude(ri => ri.Ingredient)
        .FirstOrDefault(r => r.RecipeId == recipeId);
}

原来的GetAllIngredients方法也存在同样的空引用风险,直接改成:

public IEnumerable<RecipeIngredient> GetAllIngredients(int recipeId)
{
    return context.RecipeIngredients
        .Include(ri => ri.Ingredient)
        .Where(ri => ri.RecipeId == recipeId)
        .ToList();
}

3. (推荐写法)直接操作关联表数据集

如果不需要操作Recipe实体的其他字段,完全没必要先查Recipe再给集合加数据,直接给RecipeIngredients表插入数据即可,性能更高也不会触发导航属性相关的空引用,Main方法可以改成:

static void Main(string[] args)
{
    SQLightRecipeRepository repo = new SQLightRecipeRepository();
    repo.InsertRecipeIngredient(new RecipeIngredient()
    {
        RecipeId = 1,
        IngredientId = 1,
        Measurement = Measurement.kg,
        Quantity = 2
    });
    repo.Save();
}
额外必改配置

你现在的OnModelCreating配置里没有给RecipeIngredient定义主键,EF Core运行时会直接抛出无主键异常,在OnModelCreating方法里加一段复合主键配置即可:

modelBuilder.Entity<RecipeIngredient>()
    .HasKey(ri => new { ri.RecipeId, ri.IngredientId });

这个配置同时能限制同一个食谱下不会重复添加同一个食材,符合业务逻辑。

调试结果

内容的提问来源于stack exchange,提问作者Erik Martinsson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 07:24:17