Проверьте, безопасно ли удалить строку - PullRequest
5 голосов
/ 23 ноября 2010

Я хочу иметь возможность проверить, не удастся ли удалить строку из таблицы в SQL Server 2008 из-за нарушения внешнего ключа, не пытаясь его удалить.

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

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

Я использую платформу сущностей для доступа к данным.

Ответы [ 7 ]

2 голосов
/ 23 ноября 2010

Когда вы делаете запрос, выполните левое соединение с дочерней таблицей.Используйте вычисленное значение CanDelete, чтобы решить, должна ли кнопка отображаться.COUNT здесь удаляет дубликаты, если у вас более 1 дочерней строки на родительскую строку.

SELECT
   Col1, Col2, Col3, ...,
   CASE C.Existence WHEN 0 THEN 1 ELSE 0 END AS CanDelete
FROM
   ParentTable P
   LEFT JOIN
   (
   SELECT COUNT(*) AS Existence, FKColumn
   FROM Childtable GROUP BY FKColumn
   ) C ON P.FKColumn = C.FKColumn
WHERE
   P.Col = ...

Другим способом может быть

SIGN(C.Existence) AS HasChildRows
2 голосов
/ 23 ноября 2010

Нет простого и быстрого способа проверить это.Вы, вероятно, могли бы создать что-то динамическое, используя information_schema, но это, несомненно, будет некрасиво и не очень быстро.

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

Другой вариант - начать транзакцию, попробуйте удалить.Если это не удается, то вы знаете.Если это удастся, откат транзакции, и вы знаете, что удаление возможно.Это все еще уродливо и использует транзакции в некоторой степени неэффективно, но это будет работать.Убедитесь, что каскадное удаление не включено для таблицы.

1 голос
/ 23 ноября 2010

Вы можете добавить в частичный класс вашей сущности метод, который проверял бы, существуют ли указанные объекты.

Например, допустим, у вас есть Entity1, у которого есть коллекции Entity2. По сути, в каждом из частичных классов сущности вы бы написали свойство IsReferenced, которое бы:

  • Для Entity1 вернуть true, если Entity1 имеет какой-либо элемент в Entity2
  • Для Entity2, если есть ссылка на Entity1

Как вы уже догадались, вам нужно убедиться, что вы всегда включаете ссылочные значения в выборку, или, если вы работаете в привязке к контексту, вы можете использовать .Load() в IsReferenced для выборки объектов перед проверкой. Это накладные расходы, это зависит только от того, готовы ли вы «заплатить» за это.

Затем вы можете показать / скрыть кнопку «удалить», основываясь на этом свойстве элемента, где это необходимо, что позволяет избежать необходимости повторять проверки каждый раз.

1 голос
/ 23 ноября 2010

Я делал подобные вещи в предыдущих приложениях.Я создал функцию с именем что-то вроде TryDelete ().Внутри метода я попытался удалить нужную строку.Если я получил исключение FK, я поймал его и вернул false.В любом случае, true или false, я инкапсулировал удаление в транзакции и затем откатил его.

0 голосов
/ 23 ноября 2010

Предполагая, что база данных используется несколькими пользователями (а это подавляющее большинство) - будет окно возможностей между «проверкой» возможности удаления и возможным решением пользователя удалить строку, во время которой кто-тоelse может выполнять некоторые действия, которые сводят на нет результат теста.

Это означает, что вы можете отобразить кнопку Удалить, но к тому времени, когда вы попытаетесь удалить, это больше не возможно.Кроме того, вы можете не отображать кнопку «Удалить», но к тому времени, когда пользователь решит, что он хочет удалить строку (но не может найти кнопку), ему должно быть разрешено.

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

0 голосов
/ 23 ноября 2010

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

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

0 голосов
/ 23 ноября 2010

Я думаю, что у вас есть 2 возможных варианта здесь. Так как вы не можете гарантировать, что все отношения будут отображаться в вашем ОМ, вам придется проверить его в базе данных.

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

Другим способом было бы извлечь все ограничения из таблицы sysobjects и убедиться, что в каждой таблице нет записей. Но это потребует некоторого динамического SQL, который также может стать довольно грязным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...