【问题标题】:How do you specify Cascade Delete for base tables using fluent api?如何使用 fluent api 为基表指定级联删除?
【发布时间】:2011-09-28 19:49:38
【问题描述】:

问题:如何让 EF 4.1 使用 fluent api 为基表指定外键约束上的 ON DELETE CASCADE 选项?我知道如何处理与其他表的关系,但我如何让它为 TPT(每个类型的表)表生成这个?

说明: 让我指出,我指的不是外键关系。对于我的 DbContext,我总是为我的实体使用 Mapping 对象,只是因为在大多数情况下,我更喜欢明确而不是接受约定方法。话虽如此,我的 TPT 表的所有配置都在 EntityTypeConfiguration<SomeEntityClass> 类中处理。

当我通过创建从另一个派生的新类来定义 TPT 关系时,ON DELETE CASCADE 不会在 SQL 约束中生成,这就是问题所在。

看看下面的代码...

  public class Person
  {
      public int PersonId { get; set; }
      public string Name { get; set; }
  }

  public class OtherPerson : Person
  {
      public string SomeOtherProperty { get; set; }
  }

  public class PersonMap : System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<Person>
  {
      public PersonMap()
      {
          this.HasKey(t => t.PersonId); // Primary Key

          this.Property(t => t.PersonId)
              .HasColumnName("PersonId") // Explicitly set column name
              .IsRequired() // Field is required / NOT NULL
              .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // Specify as Identity (Not necessary, but I'm explicit)

          this.Property(t => t.Name)
              .HasColumnName("Name") // Explicitly set column name
              .IsRequired() // Field is required / NOT NULL
              .HasMaxLength(50); // Max Length

          this.ToTable("People"); // Map to table name People
      }
  }

public class OtherPersonMap : System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<OtherPerson>
{
    public OtherPersonMap()
    {
        this.Property(t => t.SomeOtherProperty)
            .HasColumnName("SomeOtherProperty") // Explicitly set column name
            .IsRequired() // Field is required / NOT NULL
            .HasMaxLength(10); // Max Length

        this.ToTable("OtherPeople"); /* Map to table name OtherPeople
                                      * This also causes TPT to create a shared primary key from the base table
                                      * and double serving as a foreign key to base table.
                                      */
    }

上面的代码真的很简单。我有 2 种类型,它们在数据库中正确创建。如果我创建一个新的OtherPerson 并保存到数据库,它会正确创建 2 条记录,第一条记录在 People 表中,另一条在 OtherPeople 表中,共享主键也是 OtherPeople 的外键人们。 现在,如果我在代码中删除 OtherPerson,则 DbContext 或 EF 会正确删除两条记录。但是,如果我直接从数据库中删除记录,People 表中会留下一条孤立记录。

那么,如何为使用 fluent api 为基表生成的外键约束指定 ON DELETE CASCADE?

对不起,这个问题太长了,但我只是想尽可能地描述我的问题。 提前致谢。

【问题讨论】:

    标签: c# entity-framework-4.1 ef-code-first code-first fluent-interface


    【解决方案1】:

    现在,DbContext 或 EF 会正确删除两条记录,如果我 删除我的代码中的 OtherPerson 。但是,我应该删除 直接从数据库中记录,一个孤立的记录留在后面 人员表。

    您似乎说要从OtherPeople 表(派生实体)中删除一条记录,级联删除应确保People 表(基本实体)中的相应记录也将被删除。

    但这是错误的方向。 EF 创建从基本实体表到派生实体表的关系和外键约束,因此:PK 表是People,FK 表是OtherPeople。通过对这种关系进行级联删除,您只能确保在删除相应的 People 记录时删除 OtherPeople 记录,而不是相反。

    仅此关系 - 也没有级联删除 - 确保您无法在 OtherPeople 表中获取孤立记录,因为它会违反 FK 约束。 (如果没有相关的OtherPerson,您无法删除Person。)

    出于您的特殊目的,您实际上需要在数据库中使用第二个 FK 约束,其中 PK 表为 OtherPeople,FK 表为 People。这种关系根本不是由 EF TPT 映射创建的,而且它也只有在 People 上的 PK 不是标识时才有效(至少在 SQL Server 中)。但它是您模型中的一个身份。因此,您甚至无法在数据库中使用级联删除创建这种关系,更不用说使用 EF。

    回到 EF 在数据库中实际创建的关系(这不是您想要的级联删除关系)我认为 EF Code-First 中没有允许您控制关系的映射选项需要 TPT 映射。唯一的方法是直接在数据库中执行,或者 - 如果您想从 Code-First 模型生成数据库 - 在自定义初始化程序中编写原始 SQL 语句(设置级联删除)并将其发送到数据库在创建所有表和关系之后。

    不知何故,数据库中的People 就像Order 和OtherPeople 就像OrderItem - 只是不是1-to-* 而是1-to-0..1 关系。您想要的是,如果删除子 OrderItem,则删除父 Order,这意味着从属将删除主体。

    【讨论】:

    • 感谢您的回答。我真的希望有一种方法可以通过 api 配置它。猜猜我会在数据库中手动创建。再次感谢。
    猜你喜欢
    • 2016-03-06
    • 1970-01-01
    • 2011-05-08
    • 2014-09-26
    • 1970-01-01
    • 1970-01-01
    • 2019-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多