Запретить вставку дополнительных дочерних строк - PullRequest
0 голосов
/ 21 января 2010

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

Для одной таблицы это просто: предоставьте им привилегию INSERT только без привилегии UPDATE. Но запрос фактически охватывает две таблицы с отношением один ко многим. Мне нужно запретить пользователю вставлять дополнительные дочерние строки для существующего запроса. В идеале это должно быть реализовано на уровне базы данных: разрешить вставку родительской строки и одной или нескольких дочерних строк в той же транзакции , но как только эта транзакция будет зафиксирована, предотвратить добавление новых дочерних строк с этим внешний ключ.

Какой лучший способ добиться этого? Есть ли способы применить этот особый вид «ссылочной целостности» без триггеров? И если триггеры являются единственными, то как я могу проверить, что родительская строка была вставлена ​​в текущую транзакцию?

Ответы [ 3 ]

3 голосов
/ 21 января 2010

Хранимая процедура или триггер

Если вы предоставите права на дочернюю таблицу, они смогут писать.

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

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

1 голос
/ 21 января 2010

В следующем примере показано, как можно использовать триггер для достижения этой цели. Обратите внимание, что это не будет работать, если дочерние строки вставляются по одной внутри транзакции, а не в один оператор INSERT.

CREATE TABLE parent1
(id INT PRIMARY KEY)

CREATE TABLE child1
(id INT
,parent_id INT
)
GO

ALTER TABLE child1 ADD CONSTRAINT chilld1fk FOREIGN KEY (parent_id)
REFERENCES parent1 (id)
GO


CREATE TRIGGER trg_child1
ON child1
INSTEAD OF INSERT
AS

        SELECT parent_id
        FROM child1 AS c
        WHERE EXISTS (SELECT 1
                      FROM inserted AS i
                      WHERE i.parent_id = c.parent_id
                     )

        IF @@ROWCOUNT > 0
            BEGIN
                RAISERROR('You cannot amend this request',16,1)
            END
        ELSE        
            BEGIN
                INSERT child1
                SELECT id
                       ,parent_id
                FROM inserted
            END
GO                                                            

BEGIN TRAN
        INSERT parent1
        VALUES (1)

        INSERT child1 
        (id
        ,parent_id
        )
        SELECT 10,1
        UNION SELECT 11,1        
COMMIT

-- attempting to insert another child outside the transaction
-- will result in an error
INSERT child1
SELECT 12,1

SELECT * FROM child1
1 голос
/ 21 января 2010

Используйте хранимые процедуры для вставки данных:

  • первая хранимая процедура вставляет родительскую строку; автоматически добавляет информацию о вставке пользователя и устанавливает поле состояния,

  • вторая хранимая процедура вставляет дочерние строки после проверки родительской строки; возникает ошибка, если вызывающий пользователь не имеет права добавлять элементы в данную родительскую строку или статус родительской строки запрещает добавлять новые позиции.

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

...