Pergunta

Meu aplicativo envolve o uso de dados de envio (a "solicitação") de um formulário em um banco de dados SQL Server 2005, para revisão e aprovação posteriores por um supervisor. Os usuários devem ter permissão para inserir uma nova solicitação, mas não conseguir modificar os que já enviaram.

Com uma única tabela, isso é direto: conceda a eles o Insira apenas privilégio sem o privilégio de atualização. Mas o pedido realmente abrange duas mesas, com um relacionamento um para muitos. Preciso impedir que o usuário inserisse linhas infantis adicionais para uma solicitação existente. Idealmente, isso deve ser aplicado no nível do banco de dados: permita que uma linha pai e uma ou mais linhas infantis sejam inseridas no mesma transação, mas uma vez que essa transação é comprometida, impede que novas linhas infantis sejam inseridas com essa chave estrangeira.

Qual é a melhor maneira de conseguir isso? Existem maneiras de aplicar esse sabor especial de "integridade referencial" sem gatilhos? E se os gatilhos são apenas da maneira, como posso testar que a linha pai foi inserida na transação atual?

Foi útil?

Solução

Procedimento armazenado ou gatilho

Se você conceder direitos sobre a tabela infantil, eles poderão escrever.

Um gatilho não permitirá a gravação e um procedimento armazenado permite impedir a gravação em primeiro lugar, porque apenas o Procrações armazenadas grava nas tabelas.

Não existe uma integridade referencial "nativa" que possa capturar sua lógica de negócios porque é personalizada para sua situação.

Outras dicas

O exemplo a seguir ilustra como você pode usar um gatilho para alcançar esse comportamento. Observe que isso não funcionará se as linhas infantis forem inseridas uma de cada vez dentro da transação, e não em um único INSERT declaração.

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

Use procedimentos armazenados para inserir dados:

  • O procedimento armazenado primeiro insere a linha dos pais; Ele adiciona informações automaticamente sobre a inserção do usuário e define o campo de status,

  • O segundo procedimento armazenado insere as linhas infantis depois de verificar a linha dos pais; Isso levanta o erro se o usuário de chamada não tiver o direito de adicionar itens à linha de pai ou do status da linha pai ou da linha dos pais, não compensa a adição de novas posições.

Como alternativa, você pode usar gatilhos para fazer as verificações. Mas isso pode ser um pouco mais complicado do que chamar explicitamente os procedimentos armazenados. E as pessoas às vezes tendem a esquecer os gatilhos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top