Entity Framework一对一共享键关系下Nutrition未随父实体自动删除问题
解决方案
方案1:调整关系主体(推荐,符合一对一共享表设计)
让Nutrition作为依赖实体,复用Recipe或Ingredient的主键作为自身主键,确保每个Nutrition仅属于一个实体,同时配置级联删除:
修改实体类
public class Recipe { public int RecipeId { get; set; } public string Name { get; set; } public string Instructions { get; set; } public Nutrition Nutrition { get; set; } } public class Ingredient { public int IngredientId { get; set; } public string Name { get; set; } public Nutrition Nutrition { get; set; } } public class Nutrition { [Key] public int NutritionId { get; set; } public int Calories { get; set; } public int Protein { get; set; } public int Carbohydrates { get; set; } public int Fat { get; set; } // 每个Nutrition仅会有其中一个导航属性非空 public Recipe Recipe { get; set; } public Ingredient Ingredient { get; set; } }
修改DbContext配置
protected override void OnModelCreating(ModelBuilder modelBuilder) { // Recipe与Nutrition一对一,Recipe为主体,级联删除Nutrition modelBuilder.Entity<Recipe>() .HasOne(r => r.Nutrition) .WithOne(n => n.Recipe) .HasForeignKey<Nutrition>(n => n.NutritionId) .OnDelete(DeleteBehavior.Cascade); // Ingredient与Nutrition一对一,Ingredient为主体,级联删除Nutrition modelBuilder.Entity<Ingredient>() .HasOne(i => i.Nutrition) .WithOne(n => n.Ingredient) .HasForeignKey<Nutrition>(n => n.NutritionId) .OnDelete(DeleteBehavior.Cascade); // 添加约束,确保Nutrition只能关联单一实体 modelBuilder.Entity<Nutrition>() .HasCheckConstraint("CK_Nutrition_SingleAssociation", "[RecipeId] IS NULL OR [IngredientId] IS NULL") .HasCheckConstraint("CK_Nutrition_HasAssociation", "[RecipeId] IS NOT NULL OR [IngredientId] IS NOT NULL"); }
方案2:手动删除Nutrition(无需修改实体结构)
如果不能调整现有实体设计,可在删除Recipe/Ingredient时手动删除关联的Nutrition:
var ingredient = context.Ingredients .Include(i => i.Nutrition) .SingleOrDefault(x => x.IngredientId == id); if (ingredient != null) { context.Ingredients.Remove(ingredient); if (ingredient.Nutrition != null) { context.Nutritions.Remove(ingredient.Nutrition); } context.SaveChanges(); }
方案3:数据库触发器(适合已上线的数据库)
在数据库中创建触发器,当Recipe/Ingredient被删除时自动清理对应的Nutrition:
-- Ingredients表删除触发器 CREATE TRIGGER TR_Ingredients_CleanNutrition ON Ingredients AFTER DELETE AS BEGIN DELETE FROM Nutritions WHERE NutritionId IN (SELECT NutritionId FROM DELETED) END -- Recipes表删除触发器 CREATE TRIGGER TR_Recipes_CleanNutrition ON Recipes AFTER DELETE AS BEGIN DELETE FROM Nutritions WHERE NutritionId IN (SELECT NutritionId FROM DELETED) END
内容的提问来源于stack exchange,提问作者Simon H.
相关产品推荐
相关产品推荐

