Entity Framework Code First: ограничение FOREIGN KEY может вызвать циклы или несколько каскадных путей - PullRequest
16 голосов
/ 21 ноября 2011

Entity Framework Code First может генерировать DB для следующих POCO.

public class Item {
    public int Id { get; set; }
    public string Name { get; set; }
}

public class ItemPair {
    public int Id { get; set; }

    public virtual Item FirstItem { get; set; }
    public virtual Item SecondItem { get; set; }
}

Я бы хотел установить связь с Первым и Вторым предметом с помощью полей идентификатора, а не целого класса «Предмет». Итак:

public class ItemPair {
    public int Id { get; set; }

    public virtual Item FirstItem { get; set; }
    public int FirstItem_Id { get; set; }

    public virtual Item SecondItem { get; set; }
    public int SecondItem_Id { get; set; }
}

тоже работает. Редактировать : На самом деле это не сработало. Просто генерирует дополнительные столбцы FirstItem_Id1 и SecontItem_Id2.

Но просто изменив свойства внешнего ключа на FirstItemId, SecondItemId (без подчеркивания), вот так:

public class ItemPair {
    public int Id { get; set; }

    public virtual Item FirstItem { get; set; }
    public int FirstItemId { get; set; }

    public virtual Item SecondItem { get; set; }
    public int SecondItemId { get; set; }
}

приводит к следующему исключению.

{"Introducing FOREIGN KEY constraint 'ItemPair_SecondItem' on table 'ItemPair' may cause
cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION,
or modify other FOREIGN KEY constraints.\r\nCould not create constraint. 
See previous errors."}

Почему? И что я могу сделать, чтобы избежать этого исключения.

Ответы [ 2 ]

21 голосов
/ 23 ноября 2011

Я решил просто удалить соглашение о каскадном удалении.

 protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
        modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();

    }

Причины:

  • Я предпочитаю помечать записи как удаленные или деактивированные для целей аудита.
  • Самое большее, я удаляю только таблицы соединений / сопоставления.
  • С помощью ORM Проходить циклы и удалять дочерние записи довольно редко, если мне нужно.

Спасибо, Ладислав Мрнка, указывающий мне в правильном направлении.

17 голосов
/ 22 ноября 2011

Я ожидаю, что в первом случае ваши свойства Id не будут использоваться в базе данных, поскольку FK и EF создадут еще два столбца (вы можете проверить это, принудительно связав свойство навигации со свойством FK, используя ForeignKeyAttribute). Во втором случае EF правильно распознает ваши свойства, но также будет использовать соглашение каскадного удаления, которое приведет к ошибке на SQL-сервере. У вас есть два свойства из таблицы, указывающие на одного и того же родителя. На самом деле в базе данных вы можете создать ItemPair из того же Item (оба FK установлены на один и тот же Id). Если в обоих отношениях включено каскадное удаление, это приведет к нескольким каскадным путям =>, не разрешенным на сервере SQL.

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

...