Причина, по которой вы столкнулись с этим, связана с разницей между состав и агрегация .
В композиции дочерний объект создается при создании родителя и уничтожается при уничтожении его родителя . Таким образом, его время жизни контролируется его родителем. например Сообщение в блоге и его комментарии. Если сообщение удалено, его комментарии должны быть удалены. Не имеет смысла оставлять комментарии к несуществующему сообщению. То же самое для заказов и элементов заказа.
В агрегации дочерний объект может существовать независимо от его родителя . Если родитель уничтожен, дочерний объект все еще может существовать, так как он может быть добавлен к другому родителю позже. например: связь между списком воспроизведения и песнями в этом списке воспроизведения. Если список воспроизведения удален, песни не должны быть удалены. Они могут быть добавлены в другой список воспроизведения.
Способ, которым Entity Framework различает отношения агрегации и композиции, выглядит следующим образом:
Для композиции: ожидается, что дочерний объект будет иметь составной первичный ключ (ParentID, ChildID). Это сделано специально, так как идентификаторы детей должны быть в пределах их родителей.
Для агрегации: ожидается, что свойство внешнего ключа в дочернем объекте будет иметь значение null.
Итак, причина, по которой вы столкнулись с этой проблемой, заключается в том, как вы установили свой первичный ключ в своей дочерней таблице. Он должен быть составным, но это не так. Таким образом, Entity Framework рассматривает эту ассоциацию как агрегацию, что означает, что при удалении или очистке дочерних объектов дочерние записи не удаляются. Он просто удалит связь и установит для соответствующего столбца внешнего ключа значение NULL (чтобы эти дочерние записи впоследствии могли быть связаны с другим родителем). Поскольку ваш столбец не допускает NULL, вы получите исключение, которое вы упомянули.
Решения:
1 - Если у вас есть веская причина не использовать составной ключ, вам необходимо явно удалить дочерние объекты. И это можно сделать проще, чем предложенные ранее решения:
context.Children.RemoveRange(parent.Children);
2- В противном случае, установив правильный первичный ключ на вашей дочерней таблице, ваш код будет выглядеть более значимым:
parent.Children.Clear();