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

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.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 10:35:03