Как избежать циклических отношений в SQL-сервере? - PullRequest
0 голосов
/ 22 декабря 2009

Я создаю собственную таблицу:

Таблица Item столбцы:
ItemId int - PK;
Сумма денег - не ноль; Цена денег - вычисляемый столбец с использованием UDF, который получает значение в соответствии с суммой предков предметов.
ParentItemId int - nullable, ссылка на другой ItemId в этой таблице.

Мне нужно избегать петли, то есть брат не может стать предком своих предков, то есть если ItemId = 2 ParentItemId = 1, то ItemId 1 ParentItemId = 2 не должен быть разрешен.

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

EDIT: Другой вариант - создать триггер INSTEAD OF и ввести в 1 транзакцию обновление поля ParentItemId и выбрать поле «Цена» в @@ RowIdentity, если не удалось отменить транзакцию, но я бы предпочел проверку UDF.

Любые идеи искренне приветствуются.

Ответы [ 5 ]

1 голос
/ 22 декабря 2009

Подобные проверки нелегко осуществить, и возможные решения могут привести к множеству ошибок, а проблемы могут быть сложнее, чем первоначальные. Обычно достаточно добавить контроль для ввода пользователя и предотвратить бесконечный цикл чтения данных. Если ваше приложение использует хранимые процедуры, но не ORM, я бы решил реализовать эту логику в SP. В противном случае - обрабатывать это в других слоях, а не в DB

1 голос
/ 22 декабря 2009

Обязательно ли применять это на уровне базы данных?

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

0 голосов
/ 22 декабря 2009

Протестировано и прекрасно работает:

CREATE TRIGGER Item_UPDATE
   ON Item
   FOR INSERT, UPDATE
AS 
BEGIN

BEGIN TRY
    SELECT Price FROM INSERTED
END TRY
BEGIN CATCH
    RAISERROR('This item cannot be specified with this parent.', 16, 1)
    ROLLBACK TRANSACTION;
END CATCH

END
GO
0 голосов
/ 22 декабря 2009

Простой трюк - заставить ParentItemId быть меньше ItemId. Это предотвращает замыкание цикла в этом простом контексте.

Однако есть и обратная сторона - если вам по какой-то причине нужно удалить / вставить родителя, возможно, вам придется удалить / вставить всех его потомков по порядку.

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

0 голосов
/ 22 декабря 2009

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

Сначала подумай об этом.

...