简体   繁体   English

实体框架核心,DELETE CASCADE和[必需]

[英]Entity Framework Core, DELETE CASCADE, and [Required]

I am running into an issue DELETE CASCADE in Entity Framework Core that I can't seem to find a good solution to. 我遇到了Entity Framework Core中的问题DELETE CASCADE,我似乎无法找到一个好的解决方案。

Here's a super simplified version of my model: 这是我的模型的超简化版本:

User {UserID, Name}
Recipe {RecipeID, UserID}
Ingredient {IngredientID, UserID}
RecipeIngredient {RecipeID, IngredientID} *RecipeIngredient is the many-to-many table.

Recipe and Ingredient both have UserID marked as [Required], and RecipeIngredient has RecipeID and IngredientID marked as [Required]. 配方和成分都将UserID标记为[Required],RecipeIngredient将RecipeID和IngredientID标记为[Required]。

The issue is that SQL will not create the database because there are multiple cascade delete paths to RecipeIngredient ("Introducing FOREIGN KEY constraint... may cause cycles or multiple cascade paths"). 问题是SQL不会创建数据库,因为RecipeIngredient有多个级联删除路径(“引入FOREIGN KEY约束......可能导致循环或多个级联路径”)。

So I'm stuck... I've worked through a few ideas, but nothing has quite worked. 所以我被困了......我已经完成了一些想法,但没有任何方法可行。

  1. Is there a design solution here? 这里有设计方案吗? I'd like to keep my Foreign Keys since it makes sense to enforce it, but if there is a design solution, I'm open to it. 我想保留我的外键,因为它是有意义的强制执行它,但如果有一个设计解决方案,我愿意接受它。

  2. My next idea was to remove all FKs pointing back to User - I'd have to enforce the referential integrity during DELETE via my C# code and I could enforce the entry of the data during CREATE using [Required]. 我的下一个想法是删除指向用户的所有FK - 我必须通过我的C#代码在DELETE期间强制执行参照完整性,并且我可以在CREATE期间使用[Required]强制执行数据输入。 The problem with that - [Required] creates a FK, and adds "ON DELETE CASCADE," which puts us right back into the multiple cascade delete path problem. 问题 - [必需]创建一个FK,并添加“ON DELETE CASCADE”,这使我们回到多个级联删除路径问题。 I'd really like to keep [Required] because of the slick integration with Razor pages, client side validation and errors, etc. 我真的想保留[必需]因为与Razor页面的光滑集成,客户端验证和错误等。

  3. Next idea, set the cascade behavior to SetNull in OnModelCreating(...): 接下来的想法,在OnModelCreating(...)中将级联行为设置为SetNull:

    modelBuilder.Entity(). modelBuilder.Entity()。 HasOne(i => i.User) .WithMany(u => u.Ingredients) .OnDelete(DeleteBehavior.SetNull); HasOne(i => i.User).WithMany(u => u.Ingredients).OnDelete(DeleteBehavior.SetNull);

    modelBuilder.Entity() .HasOne(r => r.Source) .WithMany(s => s.Recipes) .OnDelete(DeleteBehavior.SetNull); modelBuilder.Entity()。HasOne(r => r.Source).WithMany(s => s.Recipes).OnDelete(DeleteBehavior.SetNull);

But this throws an exception, because even though my property in Ingredient and Recipe is set to Nullable: 但这引发了异常,因为即使我在Ingredient and Recipe中的属性设置为Nullable:

[Required(ErrorMessage = "User ID is required.")] 
public Nullable<int> UserID { get; set; }

... EF still creates it as a NOT NULL database column due to the [Required] attribute. ...由于[Required]属性,EF仍然将其创建为NOT NULL数据库列。

What's the solution for this? 这是什么解决方案? As far as I can tell, I should just remove all FKs to User, and try to enforce it as a required field on CREATE, but I don't see a way to do that with data annotations, which I'd like to do to keep this logic in my code first model. 据我所知,我应该删除所有FK到User,并尝试将其强制执行为CREATE中的必填字段,但我没有看到使用数据注释的方法,我想做将此逻辑保留在我的代码第一个模型中。

I'd recommend to disable cascade deletes as normally developers want to be very careful with what data is deleted and disabling will give you more fine grain control over your data in regards to deletion. 我建议禁用级联删除,因为通常开发人员要非常小心删除哪些数据,并且禁用将使您在删除数据时对数据进行更细粒度的控制。

You can do so in a OnModelCreation(DbModelBuilder modelBuilder) override as follows in your Context.cs class: 您可以在Context.cs类中的OnModelCreation(DbModelBuilder modelBuilder)覆盖中执行以下操作:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
  base.OnModelCreating(modelBuilder);

  modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
  modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
}

In EF Core, the Conventions class is not available, so you'll need to iterate through your entity types and restrict deletion to achieve the desired affect: 在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;
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM