SQL Server触发器干扰select语句

时间:2018-04-04 13:16:39

标签: sql sql-server entity-framework-6

我们在更新期间触发的表上有一个触发器。我们在前端使用Entity Framework。因此,我们不希望在进行更新时看到中间结果(触发器的结果)。我在触发器中设置了NOCOUNT:

ALTER TRIGGER [dbo].[trgForMedCMDWorkItemsUpdate]
   ON  [dbo].[MedCMDWorkItems]
   AFTER UPDATE
AS 
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

但是当我们执行更新时,我们首先看到中间结果,然后抛出实体框架。

这是sql命令:

Declare @UserID int
set @UserID = 26
declare @WorkItemID int
Declare @UserRoles TABLE ( roleid INT ,parentroleid INT ,rolename VARCHAR(100) )  

INSERT INTO @UserRoles  SELECT R.id,R.parentroleid,R.ROLE FROM userroles UR 
INNER JOIN roles R ON UR.roleid = R.id WHERE UR.userid = @UserID

Update MedCMDWorkItems with (UPDLOCK) Set AssignedTo = @UserID, AssignedAt = 
getdate(), LastUpdatedAt = getdate(), LastUpdatedBy = @UserID, @WorkItemID = 
ID 
where ID = (SELECT TOP 1 PR.ID FROM MedCMDWorkItems PR --with (UPDLOCK) 
JOIN TaskTypes TT on PR.TaskTypeID = TT.ID WHERE PR.AssignedTo IS NULL AND 
PR.ClosedAt IS NULL 
AND Exists (SELECT 1 FROM @UserRoles WHERE roleid in (852,772)) AND  
((PR.WorkItemTypeID = (select 29 FROM @UserRoles UR WHERE UR.RoleID = 852) 
AND TT.Task in (SELECT Substring(UR1.rolename, Charindex('|', UR1.rolename) 
+ 1, Len(UR1.rolename)) FROM @UserRoles UR1 WHERE UR1.parentroleid in (852)) 
) OR 
(PR.WorkItemTypeID = (select 28 FROM @UserRoles UR WHERE UR.RoleID = 772) 
AND TT.Task in (SELECT Substring(UR1.rolename, Charindex('|', UR1.rolename) 
+ 1, Len(UR1.rolename)) FROM @UserRoles UR1 WHERE UR1.parentroleid in (772))  
) ) 
ORDER BY (CASE WHEN PR.IsUrgent IS NULL THEN 'False' ELSE PR.IsUrgent END) 
DESC, ( CASE  WHEN PR.Priority IS NULL THEN 9999 ELSE PR.Priority END ), 
PR.CreatedAt)

Select * From MedCMDWorkItems PRI  Where ID = @WorkItemID

这是触发器:

USE [CombinedWorkflow] 
GO
/****** Object:  Trigger [dbo].[trgForMedCMDWorkItemsUpdate]    Script Date: 
4/3/2018 5:20:22 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER TRIGGER [dbo].[trgForMedCMDWorkItemsUpdate]
ON  [dbo].[MedCMDWorkItems]
AFTER UPDATE
AS 
BEGIN
SET NOCOUNT ON;

declare @NewAssignedAt DateTime;
declare @OldAssignedAt DateTime;
declare @NewPulledAt DateTime;
declare @ID int;

select @NewPulledAt = i.PulledAt from inserted i;
select @NewAssignedAt = i.AssignedAt from inserted i;
select @OldAssignedAt = d.AssignedAt from deleted d;
select @ID = i.ID from inserted i;

--If work item is being un-assigned
if(@OldAssignedAt is NOT NULL and @NewAssignedAt is NULL)
BEGIN
SET NOCOUNT ON;
Update MedCMDWorkItems 
Set PulledAt = NULL
Where  ID = @ID
END

--if work item is being assinged
ELSE if(@NewAssignedAt IS NOT NULL)
BEGIN
SET NOCOUNT ON;
Update MedCMDWorkItems 
Set FirstAssignedAt = @NewAssignedAt
Where FirstAssignedAt is NULL and ID = @ID

END


-- if work item is being pulled
ELSE if(@NewPulledAt IS NOT NULL)
BEGIN
SET NOCOUNT ON;
Update MedCMDWorkItems 
Set AssignedAt = @NewPulledAt
Where AssignedAt is NULL and ID = @ID
SET NOCOUNT ON;
Update MedCMDWorkItems 
Set FirstAssignedAt = @NewPulledAt
Where FirstAssignedAt is NULL and ID = @ID
END


Select 1
END

当我在SSMS中执行触发器结果时,我得到2个结果,首先表示1行已更新,然后是第二个表示查询结果。

如果我禁用触发器并执行命令,我不会得到第一个结果,这是我在启用触发器时所需的行为。

如何设置此触发器以使其触发但不会导致其他结果?

谢谢, 萨默尔

2 个答案:

答案 0 :(得分:0)

您需要使用inserteddeleted作为表,它们可以包含多行,因此您永远无法从中填充变量。

相反,你必须像这个例子一样构建它:

您的代码(第一部分)

ALTER TRIGGER [dbo].[trgForMedCMDWorkItemsUpdate]
ON  [dbo].[MedCMDWorkItems]
AFTER UPDATE AS 
BEGIN
  SET NOCOUNT ON;

  declare @NewAssignedAt DateTime;
  declare @OldAssignedAt DateTime;
  declare @NewPulledAt DateTime;
  declare @ID int;

  select @NewPulledAt = i.PulledAt from inserted i;
  select @NewAssignedAt = i.AssignedAt from inserted i;
  select @OldAssignedAt = d.AssignedAt from deleted d;
  select @ID = i.ID from inserted i;

  --If work item is being un-assigned
  if(@OldAssignedAt is NOT NULL and @NewAssignedAt is NULL)
  BEGIN
    SET NOCOUNT ON;
    Update MedCMDWorkItems 
    Set PulledAt = NULL
    Where  ID = @ID
  END

可以被这样的东西取代(未经测试,因为我没有你的数据库)

ALTER TRIGGER [dbo].[trgForMedCMDWorkItemsUpdate]
ON  [dbo].[MedCMDWorkItems]
AFTER UPDATE AS 
BEGIN
  SET NOCOUNT ON;

  update MedCMDWorkItems
  Set PulledAt = NULL
  where ID in ( select i.Id 
                from   Inserted i
                  left join deleted d on i.Id = d.Id
                where  d.AssignedAt is not null
                and    i.AssignedAt is null
              )  

一旦你得到这个,就不会很难弄清楚如何调整你的触发器的其余部分

答案 1 :(得分:0)

感谢大家的投入。我想出了这个问题。触发器在最后有这个:

...     END

-- if work item is being pulled
ELSE if(@NewPulledAt IS NOT NULL)
BEGIN
SET NOCOUNT ON;
Update MedCMDWorkItems 
Set AssignedAt = @NewPulledAt
Where AssignedAt is NULL and ID = @ID
SET NOCOUNT ON;
Update MedCMDWorkItems 
Set FirstAssignedAt = @NewPulledAt
Where FirstAssignedAt is NULL and ID = @ID
END


Select 1
END

不知道最后一行(选择1)应该是什么(我没有写入触发器:)),但它导致显示不需要的结果。

萨默尔