1. O que é uma trigger
Uma trigger é um bloco de T-SQL, parecido com uma procedure, mas que não é
chamado explicitamente com EXEC — ele dispara automaticamente
quando um INSERT, UPDATE ou
DELETE acontece numa tabela.
| Stored Procedure | Trigger | |
|---|---|---|
| Como é iniciada | Chamada explícita: EXEC nome | Automática, ao INSERT/UPDATE/DELETE na tabela |
| Quem decide quando rodar | Quem chama (aplicação, outra procedure) | O próprio SQL Server, sempre |
| Visibilidade no código | Explícita — aparece no código C# ou script que chama | Implícita — só olhando a tabela no SSMS você descobre que existe |
Uma trigger é lógica invisível do ponto de vista de quem escreve um
INSERT simples anos depois, sem saber que aquilo dispara uma cascata
de efeitos colaterais. É uma fonte comum de bugs difíceis de rastrear em sistemas legados. Use
triggers para auditoria e integridade — não para regra de negócio que poderia estar numa
procedure, onde fica visível.
2. AFTER vs. INSTEAD OF
| Tipo | Quando roda | Uso típico |
|---|---|---|
AFTER (ou FOR) | Depois que o comando já foi aplicado à tabela | Auditoria, sincronizar outra tabela, validação pós-fato com ROLLBACK |
INSTEAD OF | No lugar do comando original — você decide o que de fato acontece | Views que precisam aceitar INSERT/UPDATE, regras complexas de substituição |
3. As tabelas mágicas: inserted e deleted
Dentro de qualquer trigger, duas tabelas temporárias ficam disponíveis automaticamente:
inserted (linhas novas/alteradas) e deleted
(linhas antigas/removidas). Um UPDATE popula as duas ao mesmo tempo —
deleted tem o valor antigo, inserted tem o
novo.
CREATE TABLE dbo.ClienteAuditoria
(
Id INT IDENTITY(1,1) PRIMARY KEY,
ClienteId INT NOT NULL,
EmailAntigo NVARCHAR(150),
EmailNovo NVARCHAR(150),
AlteradoEm DATETIME2 NOT NULL DEFAULT SYSDATETIME()
);
GO
CREATE TRIGGER trg_Cliente_AuditarEmail
ON dbo.Cliente
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF NOT UPDATE(Email)
RETURN; -- só audita se a coluna Email realmente mudou
INSERT INTO dbo.ClienteAuditoria (ClienteId, EmailAntigo, EmailNovo)
SELECT d.Id, d.Email, i.Email
FROM deleted d
INNER JOIN inserted i ON i.Id = d.Id
WHERE d.Email <> i.Email;
END;
GO
UPDATE(Email) dentro de uma trigger não é o comando UPDATE — é uma
função que responde se aquela coluna específica foi mencionada no comando que disparou a trigger.
Um recurso pouco conhecido, mas útil para evitar processamento desnecessário.
Uma trigger dispara uma única vez por comando, não uma vez por linha — se um
UPDATE afeta 500 linhas, inserted e
deleted têm 500 linhas cada, todas de uma vez. Escrever a trigger
assumindo "uma linha só" (um erro comum de quem vem de outros bancos) quebra silenciosamente em
operações em lote.
4. Chamando uma procedure de dentro de uma trigger
É possível, e às vezes útil para reaproveitar lógica já escrita:
CREATE TRIGGER trg_Cliente_AposInserir
ON dbo.Cliente
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Id INT = (SELECT TOP 1 Id FROM inserted);
EXEC dbo.usp_NotificarNovoCliente @ClienteId = @Id;
END;
GO
O exemplo acima assume uma única linha inserida por vez (TOP 1). Se
o INSERT de origem afetar múltiplas linhas, essa trigger processaria só a primeira — um bug real
e comum. Para múltiplas linhas, prefira um cursor sobre inserted ou,
melhor ainda, redesenhar a procedure chamada para aceitar um Table-Valued Parameter (capítulo 8)
com todos os Ids de uma vez.
5. Onde isso te leva
Triggers fecham o conjunto de ferramentas de escrita do T-SQL. A partir do próximo capítulo, o foco muda de "como escrever" para "como organizar" — nomenclatura, estrutura de projeto e como tudo isso se conecta de volta à sua aplicação C#.