Как вы указываете Cascade Delete для базовых таблиц, используя свободный API? - PullRequest
0 голосов
/ 28 сентября 2011

Вопрос: Как получить в EF 4.1 указание опции ON DELETE CASCADE для ограничения внешнего ключа, используя переменный интерфейс API для базовых таблиц? Я знаю, как это сделать со связями с другими таблицами, но как мне сгенерировать это для таблиц TPT (Table Per Type)?

Описание: Позвольте мне отметить, что я не имею в виду отношения с ключевыми ключами. С моим 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 для Люди. Теперь, скорее DbContext или EF, правильно удаляет обе записи, если я удаляю OtherPerson в своем коде. Однако, если я удалю запись непосредственно из базы данных, в таблице People останется запись о сироте.

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

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

1 Ответ

0 голосов
/ 01 октября 2011

Теперь 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, что означает, что зависимый пользователь удалит участника.

...