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

发布于 2024-12-06 18:43:22 字数 2606 浏览 1 评论 0原文

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

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

当我通过创建派生自另一个类的新类来定义 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.
                                      */
    }

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

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

抱歉,问题太长了,但我只是我想尽可能地描述我的问题。 提前致谢。

Question: How do I get EF 4.1 to specify the ON DELETE CASCADE option on the foreign key constraint using the fluent api for base tables? I know how to do it with relationships to other tables, but how do I have it generate this for TPT (Table Per Type) tables?

Description:
Let me point out, I am not referring to foreign key relationships. With my DbContext I always use Mapping objects for my entities, only because in most cases I prefer to be explicit as opposed to accepting the convention approach. That being said, all the configuration for my TPT tables are being handled in the EntityTypeConfiguration<SomeEntityClass> classes.

When I define a TPT relationship by creating a new class which derives from another, the ON DELETE CASCADE does not get generated in the SQL constraint, which is the problem.

Have a look at the following code...

  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.
                                      */
    }

The above code is really simple. I have 2 types and they are correctly create in the database. If I create a new OtherPerson and save to the database it correctly creates 2 records, 1st a record in the People table and another in the OtherPeople table with a shared primary key which is also the foreign key from OtherPeople to People.
Now, the DbContext or EF rather, correctly deletes both records if I delete the OtherPerson within my code. However, should I delete the record directly from the database, an orphan record is left behind in the People table.

So, how do I get the ON DELETE CASCADE to be specified for the foreign key constraints generated for base tables using the fluent api?

Sorry the question is so long but I just wanted to describe the best I could my problem.
Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

少钕鈤記 2024-12-13 18:43:22

现在,如果我这样做,DbContext 或 EF 会正确删除两条记录
删除我的代码中的OtherPerson。但是,我应该删除
直接从数据库中记录,孤儿记录被留在
人员表。

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

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

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

出于您的特殊目的,您实际上需要在数据库中使用第二个 FK 约束,其中 PK 表为 OtherPeople< /code> ,FK 表是 People。这种关系根本不是由 EF TPT 映射创建的,并且仅当 People 上的 PK 不是身份时(至少在 SQL Server 中),它才会起作用。但它是你模型中的一个恒等式。所以你连数据库中的级联删除都无法创建这种关系,更不用说用EF了。

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

不知何故,在数据库中 People 就像 OrderOtherPeople 就像 OrderItem - 只是不是 1 - to-* 而是 1-to-0..1 关系。您想要的是,如果子 OrderItem 被删除,则父 Order 也会被删除,这意味着依赖项将删除主体。

Now, the DbContext or EF rather, correctly deletes both records if I
delete the OtherPerson within my code. However, should I delete the
record directly from the database, an orphan record is left behind in
the People table.

You seem to say that you want to delete a record from the OtherPeople table (derived entity) and cascading delete should ensure that the corresponding record in the People table (base entity) will be deleted as well.

But this is the wrong direction. EF creates a relationship and foreign key constraint which goes from the base entity table to the derived entity table, so: The PK table is People and the FK table is OtherPeople. With a cascading delete on this relationship you could only ensure that an OtherPeople record is deleted when the corresponding People record will be deleted, not the other way around.

This relationship alone - also without cascading delete - makes sure that you cannot get orphan records in the OtherPeople table because it would violate the FK constraint. (You cannot delete a Person without the related OtherPerson.)

For your special purpose you would actually need a second FK constraint in the database where PK table is OtherPeople and the FK table is People. This relationship isn't created by EF TPT mapping at all and it also would only work if the PK on People is not an identity (at least in SQL Server). But it is an identity in your model. So you can't even create this relationship with cascading delete in the database, not to mention with EF.

Back to the relationship which EF actually creates in the database (which is not the one you want with cascading delete) I don't think that there is a mapping option in EF Code-First which would allow you to control the relationship needed for TPT mapping. The only way is to do it directly in the database or - if you want to generate the database from your Code-First model - write a raw SQL statement (which sets up the cascading delete) in a custom initializer and send this to the database after all tables and relationships have been created.

Somehow in the database People is like Order and OtherPeople is like OrderItem- just not a 1-to-* but a 1-to-0..1 relationship. What you want is that the parent Order is deleted if the child OrderItem is deleted which means that the dependent will delete the principal.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文