5

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

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

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

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

ответ

2

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

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

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

1

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

2

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

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 
+0

Отличная идея! Но он использует EntityFramework для загрузки данных в объекты ... – veljkoz 2010-11-23 14:16:35

1

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

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

  • Для entity1 возвращает истину, если Entity1 имеет какой-либо элемент в entity2
  • Для entity2 возвратного ры, если есть ссылка на entity1

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

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

0

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

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

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

0

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

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

0

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

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

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

Смежные вопросы