Entity Framework .Remove () против .DeleteObject ()

142

Вы можете удалить элемент из базы данных с помощью EF, используя следующие два метода.

Первый - на, EntityCollectionа второй - на ObjectContext.

Когда следует использовать каждый?

Одно предпочтительнее другого?

Remove()возвращает boolи DeleteObject()возвращает void.

Сэм Лич
источник

Ответы:

277

В целом неправильно, что вы можете « удалить элемент из базы данных » обоими методами. Если быть точным, это так:

  • ObjectContext.DeleteObject(entity)помечает объект какDeleted в контексте. (Это EntityStateбудет Deletedпосле этого.) Если вы позвоните SaveChangesпозже, EF отправит DELETEинструкцию SQL в базу данных. Если никакие ссылочные ограничения в базе данных не нарушаются, объект будет удален, в противном случае выдается исключение.

  • EntityCollection.Remove(childEntity)отмечает отношения между родителем и childEntityasDeleted . Если childEntityсам удаляется из базы данных, и что именно происходит при вызове, SaveChangesзависит от типа отношений между ними:

    • Если связь является необязательной , т. Е. Внешний ключ, который ссылается от дочернего к родительскому в базе данных, допускает NULLзначения, этот внешний будет установлен в нуль, и если вы вызовете SaveChangesэто NULLзначение для, childEntityбудет записано в базу данных (то есть отношение между два удаляются). Это происходит с оператором SQL UPDATE. Никакого DELETEзаявления не происходит.

    • Если связь требуется (FK не допускает NULLзначений) и связь не идентифицируется (что означает, что внешний ключ не является частью дочернего (составного) первичного ключа), вам необходимо либо добавить дочерний элемент к другому родительскому элементу, либо вы должны явно удалить ребенка (с помощью DeleteObjectthen). Если вы не сделаете ничего из этого, ссылочное ограничение будет нарушено, и EF выдаст исключение при вызове SaveChanges- печально известное исключение « Связь не может быть изменена, потому что одно или несколько свойств внешнего ключа не допускают значения NULL » или аналогичный.

    • Если отношения идентификации (это обязательно требуется , то потому , что какая - либо часть первичного ключа не может быть NULL) EF будет отмечать , childEntityкак Deletedи. При вызове SaveChangesSQL- запрос DELETEбудет отправлен в базу данных. Если никакие другие ссылочные ограничения в базе данных не нарушаются, сущность будет удалена, в противном случае выдается исключение.

На самом деле я немного смущен разделом «Примечания» на странице MSDN, которую вы связали, потому что в нем говорится: « Если отношение имеет ограничение ссылочной целостности, вызов метода Remove для зависимого объекта помечает и отношение, и зависимый объект для удаления. ". Мне это кажется неточным или даже неправильным, потому что все три приведенных выше случая имеют « ограничение ссылочной целостности », но только в последнем случае фактически удален дочерний элемент. (Если только они не означают под « зависимым объектом » объект, который участвует в идентифицирующих отношениях, что, однако, было бы необычной терминологией.)

Slauma
источник
2
Википедия ссылочной целостности: ссылочная целостность - это свойство данных, которое, когда выполняется, требует, чтобы каждое значение одного атрибута (столбца) отношения (таблицы) существовало как значение другого атрибута в другом (или таком же) отношении (таблица ), поэтому, когда отношения являются необязательными, мы нарушаем правило целостности данных
Мохаммадреза
3
@Mohammadreza: Если вы интерпретируете NULLкак «Не значение» (вместо «значение NULL», как я писал иногда немного небрежно), то «необязательное отношение» не противоречит этому определению ссылочной целостности.
Slauma
1
Так что же за версия EF Core ObjectContext.DeleteObject?
Джонатан Аллен
13

Если вы действительно хотите использовать Deleted, вам придется сделать свои внешние ключи обнуляемыми, но тогда вы получите потерянные записи (что является одной из основных причин, по которой вы не должны этого делать в первую очередь). Так что просто используйтеRemove()

ObjectContext.DeleteObject (entity) отмечает объект как удаленный в контексте. (После этого EntityState удаляется.) Если после этого вы вызываете SaveChanges, EF отправляет SQL-запрос DELETE в базу данных. Если никакие ссылочные ограничения в базе данных не нарушаются, объект будет удален, в противном случае выдается исключение.

EntityCollection.Remove (childEntity) помечает связь между parent и childEntity как удаленную. Если сам childEntity удален из базы данных, и что именно происходит при вызове SaveChanges, зависит от типа отношений между ними:

Стоит отметить, что настройка .State = EntityState.Deleted не вызывает автоматически обнаруживаемых изменений. ( архив )

Матас Вайткявичюс
источник
4
Хорошо, для тех, кто отрицает мой ответ, это не имеет ничего общего с ответом Слаумы - они оба указывают на одну и ту же документацию . Майн объясняет примеры из реальной жизни, а его теория - часть этого.
Матас Вайткявичюс