如何使用fluent api为基表指定级联删除

本文关键字:级联 删除 基表 何使用 fluent api | 更新日期: 2023-09-27 18:10:10

问题:我如何让EF 4.1使用流利的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到People的外键。现在,如果我在代码中删除OtherPerson, DbContext或EF就会正确地删除这两条记录。但是,如果我直接从数据库中删除该记录,则会在People表中留下一条孤儿记录。

那么,我如何得到ON DELETE CASCADE被指定为使用流利的api生成的基表的外键约束?

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

如何使用fluent api为基表指定级联删除

现在,DbContext(更确切地说是EF)正确地删除了这两个记录,如果I删除我的代码中的OtherPerson。但是,我是否应该删除记录直接从数据库中取出,孤儿记录则留在数据库中

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

但这是错误的方向。EF创建了一个从基本实体表到派生实体表的关系和外键约束,因此:PK表为People, FK表为OtherPeople。在此关系上使用级联删除,您只能确保在相应的People记录被删除时删除OtherPeople记录,而不是相反。

这个关系本身——也没有级联删除——确保你不能在OtherPeople表中获得孤儿记录,因为它会违反FK约束。(删除Person时不能删除相应的OtherPerson)

对于您的特殊目的,您实际上需要在数据库中添加第二个FK约束,其中PK表为OtherPeople, FK表为People。这种关系根本不是由EF TPT映射创建的,它也只会在People上的PK不是一个身份(至少在SQL Server中)时才会起作用。但它是你模型中的一个身份。所以你甚至不能在数据库中使用级联删除来创建这种关系,更不用说EF了。

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

在数据库中,PeopleOrder很像,OtherPeopleOrderItem很像,只是不是1-to-*,而是1-to-0..1的关系。您想要的是,如果子OrderItem被删除,则父Order被删除,这意味着依赖将删除主体。