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
相关产品推荐
相关产品推荐

