Как указать Cascade Delete для базовых таблиц с помощью Fluent API?

Вопрос. Как заставить EF 4.1 указать параметр ON DELETE CASCADE для ограничения внешнего ключа с помощью API Fluent для базовых таблиц? Я знаю, как это сделать с отношениями к другим таблицам, но как мне сгенерировать это для таблиц 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 записи, 1-ю запись в таблице People и другую в таблице OtherPeople с общим первичным ключом, который также является внешним ключом от OtherPeople к People. Теперь DbContext или EF корректно удаляют обе записи, если я удаляю OtherPerson в своем коде. Однако если я удалю запись непосредственно из базы данных, потерянная запись останется в таблице People.

Итак, как мне указать ON DELETE CASCADE для ограничений внешнего ключа, сгенерированных для базовых таблиц с помощью Fluent API?

Извините, что вопрос такой длинный, но я просто хотел описать как можно лучше свою проблему. Заранее спасибо.


person Jason.Net    schedule 28.09.2011    source источник


Ответы (1)


Теперь DbContext или EF корректно удаляют обе записи, если я удаляю OtherPerson в своем коде. Однако если я удалю запись непосредственно из базы данных, потерянная запись останется в таблице «Люди».

Кажется, вы говорите, что хотите удалить запись из таблицы OtherPeople (производный объект), и каскадное удаление должно гарантировать, что соответствующая запись в таблице People (базовый объект) также будет удалена.

Но это неверное направление. EF создает связь и ограничение внешнего ключа, которое переходит из таблицы базовых сущностей в таблицу производных сущностей, поэтому: таблица PK — People, а таблица FK — OtherPeople. При каскадном удалении этого отношения вы можете гарантировать, что запись OtherPeople будет удалена только тогда, когда соответствующая запись People будет удалена, а не наоборот.

Только это отношение — также без каскадного удаления — гарантирует, что вы не сможете получить потерянные записи в таблице OtherPeople, потому что это нарушит ограничение FK. (Вы не можете удалить Person без связанного OtherPerson.)

Для вашей специальной цели вам действительно понадобится второе ограничение FK в базе данных, где таблица PK - OtherPeople, а таблица FK - People. Эта связь вообще не создается сопоставлением EF TPT, и она также будет работать, только если PK на People не является идентификатором (по крайней мере, в SQL Server). Но это личность в вашей модели. Таким образом, вы даже не можете создать эту связь с каскадным удалением в базе данных, не говоря уже об EF.

Вернемся к отношениям, которые EF фактически создает в базе данных (это не то, что вы хотите с каскадным удалением). Я не думаю, что в EF Code-First есть параметр сопоставления, который позволил бы вам контролировать отношения, необходимые для TPT отображение. Единственный способ — сделать это непосредственно в базе данных или — если вы хотите создать базу данных из вашей модели Code-First — написать необработанный оператор SQL (который настраивает каскадное удаление) в пользовательском инициализаторе и отправить его в базу данных. после создания всех таблиц и связей.

Каким-то образом в базе данных People похоже на Order, а OtherPeople на OrderItem, только отношение не 1-to-*, а 1-to-0..1. Вы хотите, чтобы родительский Order удалялся, если дочерний OrderItem удалялся, что означает, что зависимый удалит принципала.

person Slauma    schedule 30.09.2011
comment
Спасибо за ответ. Я очень надеялся, что будет способ настроить его через API. Думаю, я вручную создам в базе данных. Еще раз спасибо. - person Jason.Net; 03.10.2011