【问题标题】:How Entity Framework 6 decides if the FK should be defined with ON DELETE CASCADEEntity Framework 6 如何决定是否应该使用 ON DELETE CASCADE 定义 FK
【发布时间】:2018-12-16 19:19:09
【问题描述】:

我有一堆彼此相关的类。

我们以下面的类层次结构为例:

Class A
{
    // PK
    public string A_Id

    // Navigation Property
    public virtual ICollection<B> MyB{ get; set; }
}


Class B
{
    // PK
    public int B_Id

    // FK - On Delete - NO ACTION     <---------- Difference here
    public string A_Id { get; set; }

    // Navigation Properties
    public virtual A MyA { get; set; }
    public List<C> MyC{ get; set; }
}

Class C
{
    // PK
    public int C_Id

    // FK - On Delete - CASCADE     <---------- Difference here
    public int B_Id { get; set; }

    // Navigation Properties
    public virtual B MyB { get; set; }
}

当我在 SQL Management Studio 中检查 FK 时,我看到 On delete cascade 是在 Class C 的 FK 上定义的,但不是在 Class B 的 FK 上强>。

此外,当我尝试删除 A 的一个实例时,我会得到不同的运行时异常,因为存在引用该实例的行。

为什么会这样?

我应该如何将它们都定义为 On Delete Cascade?​​p>

EF6 如何确定如何定义 FK??

我已经阅读了许多 SO 答案,但都没有成功。

我也尝试使用 Fluent API 定义 FK,但它只是创建了第二个 FK,而不是修改第一个。 =[

【问题讨论】:

    标签: c# sql .net database entity-framework-6


    【解决方案1】:

    好吧,经过一番努力,这里是正确的答案:

    实体框架默认行为是“删除级联”

    但是只有当列是Non-Nullable时才能定义“ON DELETE CASCADE”。

    所以如果我们回到这个例子,我们可以看到 A 类有一个 string PK (nullable),而 B 类有一个 int PK(不可为空)。这就解释了差异。

    如何解决?

    最好的解决办法是在上面设置一个[Required]属性 FK 属性,否则,EF6 引擎将把该属性视为 可以为空并定义删除时 -> 无操作!

    工作示例:

    Class A
    {
        // PK
        public string A_Id
    
        // Navigation Property
        public virtual ICollection<B> MyB{ get; set; }
    }
    
    
    Class B
    {
        // PK
        public int B_Id
    
        // FK - On Delete - NO ACTION     <---------- Difference here
        [Required]          <------------------------ SOLUTION =] =] =]
        public string A_Id { get; set; }
    
        // Navigation Properties
        public virtual A MyA { get; set; }
        public List<C> MyC{ get; set; }
    }
    
    Class C
    {
        // PK
        public int C_Id
    
        // FK - On Delete - CASCADE     <---------- Difference here
        public int B_Id { get; set; }
    
        // Navigation Properties
        public virtual B MyB { get; set; }
    }
    

    【讨论】:

      【解决方案2】:

      在您的 DbContext 类中,您可以像这样使用 FluentAPI 完成此操作:

       protected override void OnModelCreating(DbModelBuilder modelBuilder)
          {
              modelBuilder.Entity<A>()
                  .HasOptional(a => a.MyB)
                  .WithOptionalDependent()
                  .WillCascadeOnDelete(true);
          }
      

      它也让您可以灵活地使用非必填字段。

      【讨论】:

      • 嗨,我尝试过使用 FluentAPI(正如我在问题中提到的那样)。它创建了不需要的第二个 FK 的问题。您的代码是否创建了新的 FK?我用这个:entityframeworktutorial.net/code-first/…
      • @Yitzchak 你说的“它创造了第二个 FK”是什么意思?帮助我理解
      • 好的,现在我明白了,当您使用代码优先时,您可以通过保持正确的命名约定来设置表关系。如果您不想像 EF 期望的那样命名您的属性,那么您应该使用以下方式之一创建关系: 1. 使用注释(如 ForeignKey 注释) 2. 使用 Fluent Api。在我的例子中,我用注释定义了我的键,所以当我添加 Fluent Api 代码时,我得到了比需要更多的 FK。 (从 B 类我有 2 个 FK 到 A 类的 ID)
      • 是的没错,导航属性基本上是在幕后为你创建了一个外键。
      • +1 表示正确答案,您的答案确实出现在其他 SO 帖子中,我的帖子的目的是了解幕后的 EF,以便开发人员可以为他选择最佳解决方案。
      猜你喜欢
      • 2011-09-21
      • 2012-11-04
      • 2014-03-09
      • 1970-01-01
      • 1970-01-01
      • 2013-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多