I have the following trigger for Auditing.
CREATE OR ALTER TRIGGER dbo.TR_MyTrigger ON dbo.Cust
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @EntityState AS SMALLINT;
SET @EntityState = (CASE
WHEN EXISTS(SELECT * FROM INSERTED) AND EXISTS(SELECT * FROM DELETED) THEN 3 -- Updated
WHEN EXISTS(SELECT * FROM INSERTED) THEN 4 -- Inserted
WHEN EXISTS(SELECT * FROM DELETED) THEN 2 -- Deleted
ELSE NULL END)
IF @EntityState = 4
BEGIN
UPDATE Cust
SET Created = GETDATE(), Updated = GETDATE()
FROM INSERTED I
WHERE Cust.BinId = I.BinId
END
ELSE IF @EntityState = 3
BEGIN
UPDATE Cust
SET Updated = GETDATE()
FROM INSERTED I
WHERE Cust.BinId = I.BinId
END
IF @EntityState <> 2
BEGIN
INSERT INTO AuditEntries (SomeColumns..)
SELECT SomeColumns..
FROM INSERTED I;
END
ELSE
BEGIN
INSERT INTO AuditEntries (SomeColumns..)
SELECT SomeColumns..
FROM DELETED I;
END
END;
When the client(API Server) call writing to the table Cust
is complete, the next call inserts userIds
to the AuditEntries
table.
Extra info:
- There exist no other triggers anywhere.
- Client uses EntityFramework Core so time in question is after
SaveChangesAsync()
returns. - The PrimaryKey of the
AuditEntries
table is theROWVERSION
ofdbo.Cust
The question is: are the AuditEntries
guaranteed to exist at this time or is this a race I need to handle?
Other research:
An answer to: Are Sql Triggers synchronous or asynchronous
UPDATE: The above trigger does not enter a loop via direct recursion on any update operations due to the default T-Sql configuratoin. See: Recursive Triggers
Found an SO this am that answers my original question: Does a trigger in a transaction only fire when the transaction is committed?
Best Answer
DELTE the UPDATE from your trigger
When you delete the UPDATE trigger Case 4 and 3 wouldn't fire the trigger again.
So only when you INSERT or DELETE, the trigger would run, and update Cust or insert into AuditEntries
With this AFTER UPDATE TRiGGER you would create a loop.
so you should write another triigger only for UPDATES, if you need one.
To answer your question
The trigger would run after the INSER or DELETE of dbo.Cust and will run completely before starting another command, that is because you define your trigger as FOR EACH STATEMENT
As Example
Every step is completed before the next