我现在有了解决方案,让我们用一个完整的例子来做一个学校案例。 :)
在这个例子中,我们的应用程序是一个地址簿。我们要更新业务活动(业务中的 IsActive 列)
每次我们添加、更新或删除此业务的联系人时。如果至少有一个联系人,则该业务被视为活跃
的业务是活跃的。我们将业务的每个状态变化记录在一张表中,以获取完整的历史记录。
所以,我们有 3 张桌子:
表业务(标识符(PK Identity)、名称、IsActive)、
表联系人(标识符(PK 身份)、姓名、IsActive、IdentifierBusiness)
表BusinessHistory(标识符(PK Identity)、IsActive、Date、IdentifierBusiness)
这是我们感兴趣的触发器:
表联系人(触发 IoInsert):
-- inserting the new rows
INSERT INTO Contact
(
Name
,IsActive
,IdentifierBusiness
)
SELECT
t0.Name
,t0.IsActive
,t0.IdentifierBusiness
FROM
inserted AS t0
-- Updating the business
UPDATE
Business
SET
IsActive = CASE WHEN
(
(t0.IsActive = 1 AND Business.IsActive = 1)
OR
(t0.IsActive = 1 AND Business.IsActive = 0)
) THEN 1 ELSE 0
FROM
inserted AS t0
WHERE
Business.Identifier = t0.IdentifierBusiness
AND
t0.IsActive = 1
AND
Business.IsActive = 0
-- Forcing rowCount for EntityFramework
DECLARE @Identifier BIGINT;
SET @Identifier = scope_identity()
SELECT @Identifier AS Identifier
表业务(触发 IoUpdate)
UPDATE
Business
SET
IsActive = 1
FROM
Contact AS t0
WHERE
Business.Identifier = t0.IdentifierBusiness
AND
t0.IsActive = 1
AND
Business.IsActive = 0
---- Updating BusinessHistory
INSERT INTO BusinessHistory
(
Date
,IsActive
,IdentifierBusiness
)
SELECT
DATE()
,t0.IsActive
,t0.Identifier
FROM
inserted AS t0
INNER JOIN
deleted AS t1 ON t0.Identifier = t1.Identifier
WHERE
(t0.Identifier <> t1.Identifier)
-- Forcing rowCount for EntityFramework
CREATE TABLE #TempTable (temp INT PRIMARY KEY);
INSERT INTO #TempTable VALUES (1);
DROP TABLE #TempTable
表业务历史:
-- Updating the business
UPDATE
Business
SET
IsActive = CASE WHEN
(
(t0.IsActive = 1 AND Business.IsActive = 1)
OR
(t0.IsActive = 1 AND Business.IsActive = 0)
) THEN 1 ELSE 0
FROM
inserted AS t0
WHERE
Business.Identifier = t0.IdentifierBusiness
AND
t0.IsActive = 1
AND
Business.IsActive = 0
-- inserting the new rows
INSERT INTO BusinessHistory
(
Date
,IsActive
,IdentifierBusiness
)
SELECT
DATE()
,t0.IsActive
,t0.Identifier
FROM
inserted AS t0
-- Forcing rowCount for EntityFramework
DECLARE @Identifier BIGINT;
SET @Identifier = scope_identity()
SELECT @Identifier AS Identifier
那么,简而言之,发生了什么?
我们有 2 张桌子,Business 和 Contact。联系人在插入和更新时更新表业务。
当Business被更新时,它会插入BusinessHistory,存储表Business的更新历史
,当字段 IsActive 更新时。
问题是,即使我没有在 BusinessHistory 中插入新行,我也会启动插入指令,因此,我会进入表 BusinessHistory 的而不是插入触发器。当然,在这个的最后,还有一个scope_identity()。您只能使用一次 scope_identity,它会返回最后插入的身份。
因此,由于我没有插入任何 BusinessHistory,它正在消耗我新插入的联系人的 scope_identity :而不是的 scope_identity
联系人表的插入为空!
如何隔离问题?
如何解决?
这里有几种选择。我所做的是在表 Business 中通过 If 条件插入 BusinessHistory :
我希望仅当状态“IsActive”已更改时才插入插入:
IF EXISTS
(
SELECT
1
FROM
inserted AS t0
INNER JOIN
deleted AS t1 ON t0.Identifier = t1.Identifier
WHERE
(t0.IsActive <> t1.IsActive)
)
BEGIN
INSERT INTO BusinessHistory
(
Date
,IsActive
,IdentifierBusiness
)
SELECT
DATE()
,t0.IsActive
,t0.Identifier
FROM
inserted AS t0
INNER JOIN
deleted AS t1 ON t0.Identifier = t1.Identifier
WHERE
(t0.IsActive <> t1.IsActive)
END
另一种可能性是,在触发器中,而不是插入表 BusinessHistory,用 IF EXISTS 条件包围整个触发器
IF EXISTS (SELECT 1 FROM inserted)
BEGIN
----Trigger's code here !
END
如何避免?
- 好吧,使用这些修复程序之一!
- 避免 scope_identity(),@@IDENTITY 在大多数情况下绰绰有余!在我的公司,我们只使用 scope_identity 因为 EF 4 !
我知道我的英语并不完美,如果它不够好,或者如果有人想在这个主题上添加一些东西,我可以编辑!