我在使用entityFramework 4时遇到了一些麻烦。这是事情: 我们有一个SQL服务器数据库。每个表都有3个而不是触发器用于插入,更新和删除。 我们知道EntityFramework有一些问题需要处理这些触发器,这就是为什么我们在触发器的末尾添加以下代码来强制执行rowCount:
表示插入:
DECLARE @Identifier BIGINT;
SET @Identifier = scope_identity()
SELECT @Identifier AS Identifier
更新/删除:
CREATE TABLE #TempTable (temp INT PRIMARY KEY);
INSERT INTO #TempTable VALUES (1);
DROP TABLE #TempTable
直到现在一切正常: 从而不是插入触发器(让我们说表A),我尝试更新另一个表的字段(表B)
我知道我的更新代码完全有效,因为手动插入可以完成工作。只有在我使用实体框架时才会出现问题。
答案 0 :(得分:1)
我现在有了解决方案,让我们以一个完整的例子来说明这个案例。 :)强>
在这个例子中,我们的应用程序是一个addressBook。我们想要更新业务活动(业务中的IsActive列) 每次我们添加,更新或删除此业务的联系人。如果至少有一个联系人,则该业务被视为有效 业务活跃。我们在表格中记录业务的每个州变更,以获得完整的历史记录。
所以,我们有3个表:
表业务(标识符(PK Identity),名称,IsActive), 表联系人(标识符(PK Identity),名称,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
表BusinessHistory:
-- 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更新时,它会插入BusinessHistory,它存储表Business的更新历史记录 ,当IsActive字段更新时。
问题是,即使我没有在BusinessHistory中插入新行,我也会启动一个插入指令,因此,我进入了BusinessHistory表的insert而不是insert触发器。当然,在这个结尾,有一个scope_identity()。您只能使用scope_identity一次,并返回插入的最后一个标识。 因此,由于我没有插入任何BusinessHistory,因此消耗了我新插入的联系人的scope_identity:而不是使用scope_identity而不是 联系表的插入是空的!
如何隔离问题?
使用分析器,您可以发现BusinessHistory中存在插入指令,而不应该是其中任何一个。
使用调试,您最终将以不应该进入的插入触发器结束。
如何解决?
这里有几种选择。我所做的是在表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
如何避免?
我知道我的英语不完美,如果不够好我可以编辑,或者有人想在这个主题上添加一些内容!