EF6.0 "Отношение не может быть изменено, поскольку одно или несколько свойств внешнего ключа не могут быть равны нулю"

Если я пытаюсь удалить "дочернюю" строку, я всегда получаю исключение. Вот фрагмент кода:

using (var context = new CompanyContext())
{
    ItemType itemType = context.ItemTypes.FirstOrDefault(i => i.Name == "ServerType");
    ItemTypeItem itemTypeItem = itemType.Items.FirstOrDefault(i => i.Name == "DatabaseServer");
    itemType.Items.Remove(itemTypeItem);
    context.SaveChanges(); <=== exception!
}

Следующее исключение брошено на SaveChanges() метод.

"Отношение не может быть изменено, поскольку одно или несколько свойств внешнего ключа не могут иметь значение NULL. Когда изменение вносится в отношение, связанному свойству внешнего ключа присваивается нулевое значение. Если внешний ключ делает не поддерживает нулевые значения, должно быть определено новое отношение, свойству внешнего ключа должно быть назначено другое ненулевое значение или не связанный объект должен быть удален."

Конфигурация объекта

  public class ItemTypeConfiguration : NamedEntityConfiguration<ItemType>
  {
    public ConfigurationColumn ParentIDColumn;
    public ConfigurationColumn ValidationPatternColumn;
    public ItemTypeConfiguration() : base()
    {
      ParentIDColumn = new ConfigurationColumn() { Name = "ParentID", Ordinal = base.LastOrdinalPosition + 1 };
      ValidationPatternColumn = new ConfigurationColumn() { Name = "ValidationPattern", Length = 1024, Ordinal=base.LastOrdinalPosition + 2};
      this.Property(t => t.ParentID)
        .HasColumnName(ParentIDColumn.Name)
        .HasColumnOrder(ParentIDColumn.Ordinal);
      this.HasOptional(t => t.Parent).WithMany().HasForeignKey(u => u.ParentID).WillCascadeOnDelete(false);
      this.Property(t => t.ValidationPattern)
        .HasColumnName(ValidationPatternColumn.Name)
        .HasColumnOrder(ValidationPatternColumn.Ordinal)
        .HasMaxLength(ValidationPatternColumn.Length);
    }
...


  public class ItemTypeItemConfiguration : NamedEntityConfiguration<ItemTypeItem>
  {
    public ConfigurationColumn ItemTypeIDColumn;
    public ItemTypeItemConfiguration() : base()
    {
      ItemTypeIDColumn = new ConfigurationColumn(){Name="ItemTypeID", IsRequired=true, Ordinal= base.LastOrdinalPosition+1};
      this.Property(t => t.ItemTypeID)
        .HasColumnName(ItemTypeIDColumn.Name)
        .HasColumnOrder(ItemTypeIDColumn.Ordinal);
      this.HasRequired(t => t.ItemType).WithMany(t=>t.Items).HasForeignKey(u => u.ItemTypeID).WillCascadeOnDelete(true);
    }
...

Я нашел блог, но у меня нет метода "DeleteObject".

http://blog.clicdata.com/2013/07/04/the-operation-failed-the-relationship-could-not-be-changed-because-one-or-more-of-the-foreign-key-properties-is-non-nullable/

Есть идеи? Спасибо.

5 ответов

Решение

Вам необходимо удалить ItemTypeItem. Невозможно просто удалить его из списка элементов, так как он не может существовать сам по себе, поскольку у него есть необнуляемый внешний ключ, ссылающийся на ItemType (ItemTypeID).

Для удаления ItemTypeItem добавьте

context.Entry(itemTypeItem).State = EntityState.Deleted;

В платформе сущностей 6.0, если вы удалите сущность из основного набора контекста, она будет работать. Например, чтобы удалить инвестиционную организацию, вы должны сделать следующее:

context.Investments.Remove(entity);
context.SaveChanges();

Это отличается от попытки удалить объект от его родителя / владельца, как показано ниже:

bankAccount.Investments.Remove(entity);
context.SaveChanges();

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

В сущности 6.0 существует разница между:

context.Investments.Remove(entity);

а также

context.Entry(entity).State = EntityState.Deleted;

При использовании первого и включенном каскадном удалении EF самостоятельно выполнит необходимое удаление дочерних коллекций. При использовании второго параметра EF не будет обрабатывать необходимые удаления, но позволит вам выполнить повторное связывание / удаление этих дочерних объектов.

Эта проблема возникает из-за того, что мы пытаемся удалить родительскую таблицу, но данные дочерней таблицы присутствуют. Мы решаем проблему с помощью каскадного удаления.

В модели Create метод в классе dbcontext.

 modelBuilder.Entity<Job>()
                .HasMany<JobSportsMapping>(C => C.JobSportsMappings)
                .WithRequired(C => C.Job)
                .HasForeignKey(C => C.JobId).WillCascadeOnDelete(true);
            modelBuilder.Entity<Sport>()
                .HasMany<JobSportsMapping>(C => C.JobSportsMappings)
                  .WithRequired(C => C.Sport)
                  .HasForeignKey(C => C.SportId).WillCascadeOnDelete(true);

После этого в нашем API Call

var JobList = Context.Job                       
          .Include(x => x.JobSportsMappings)                                     .ToList();
Context.Job.RemoveRange(JobList);
Context.SaveChanges();

Каскадная опция удаления удаляет родительскую, а также родительскую дочернюю таблицу с помощью этого простого кода. Попробуй так просто.

Удалить диапазон, который используется для удаления списка записей в базе данных Спасибо

Другие ответы , описывающие , почему происходит ошибка правильно, но это на самом деле можно получить EF полностью удалить ребенок , когда .Removeвызывается для коллекции дочерних объектов родительского объекта, вам не нужно переходить непосредственно к таблице дочерних объектов в контексте БД и удалять ее из нее.

Чтобы это сработало, вам необходимо настроить идентифицирующую связь, как описано в этом ответе .

Другие вопросы по тегам