我遇到了Entity Framework Core中的问题DELETE CASCADE,我似乎无法找到一个好的解决方案。
这是我的模型的超简化版本:
User {UserID, Name}
Recipe {RecipeID, UserID}
Ingredient {IngredientID, UserID}
RecipeIngredient {RecipeID, IngredientID} *RecipeIngredient is the many-to-many table.
配方和配料都将UserID标记为[Required],RecipeIngredient将RecipeID和IngredientID标记为[Required]。
问题是SQL不会创建数据库,因为RecipeIngredient有多个级联删除路径(“引入FOREIGN KEY约束......可能导致循环或多个级联路径”。)
所以我被困了......我已经完成了一些想法,但没有什么能够奏效。
这里有设计方案吗?我想保留我的外键,因为它是有意义的强制执行它,但如果有设计解决方案,我愿意接受它。
我的下一个想法是删除指向用户的所有FK - 我必须通过我的C#代码在DELETE期间强制执行引用完整性,我可以使用[Required]强制在CREATE期间输入数据。问题 - [必需]创建一个FK,并添加“ON DELETE CASCADE”,这使我们回到多个级联删除路径问题。由于与Razor页面的光滑集成,客户端验证和错误等,我真的想保留[必需]。
接下来的想法,在OnModelCreating(...)中将级联行为设置为SetNull:
modelBuilder.Entity()。 HasOne(i => i.User) .WithMany(u => u.Ingredients) .OnDelete(DeleteBehavior.SetNull);
modelBuilder.Entity() .HasOne(r => r.Source) .WithMany(s => s.Recipes) .OnDelete(DeleteBehavior.SetNull);
但这引发了异常,因为即使我在Ingredient and Recipe中的属性设置为Nullable:
[Required(ErrorMessage = "User ID is required.")]
public Nullable<int> UserID { get; set; }
...由于[Required]属性,EF仍然将其创建为NOT NULL数据库列。
这是什么解决方案?据我所知,我应该删除所有FK到User,并尝试将其强制执行为CREATE中的必填字段,但我没有看到使用数据注释的方法,我想做将此逻辑保留在我的代码第一个模型中。
答案 0 :(得分:6)
我建议禁用级联删除,因为通常开发人员要非常小心删除哪些数据,并且禁用将使您在删除数据时对数据进行更细粒度的控制。
您可以在OnModelCreation(DbModelBuilder modelBuilder)
类的Context.cs
覆盖中执行此操作,如下所示:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
}
在EF Core中,Conventions
类不可用,因此您需要遍历实体类型并限制删除以实现所需的效果:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
foreach (var relationship in builder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
{
relationship.DeleteBehavior = DeleteBehavior.Restrict;
}
}