EF4 RowCount问题,而不是插入触发器,而更新其他表
我有一些entityFramework 4的麻烦。这里是: 我们有一个SQL服务器数据库。每个表都有3个而不是触发器来插入,更新和删除。 我们知道的EntityFramework有一些问题需要处理论文触发器,这就是为什么我们在触发器的末尾添加以下代码强制根据rowCount:EF4 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
它工作得很好至今: 从不是INSERT触发器(假设表A),我尝试更新的其他表的字段(表B)
我知道我的更新代码完美的工作,因为手动插入完成工作。只有当我使用实体框架时才会出现问题。
我现在有解决方案,让我们用一个完整的例子来做一个这样的学校案例。 :)
在这个例子中,我们的应用程序是一个地址簿。我们希望每次添加,更新或删除该业务的联系人时更新业务活动(业务中的IsActive列) 。如果业务的至少一个联系人 处于活动状态,则认为该业务处于活动状态。我们在表格中记录企业的每个状态变化,以获得完整的历史记录。
所以,我们有3个表:
表业务(标识符(PK身份),姓名,IsActive), 表联系(标识符(PK身份),姓名,IsActive,IdentifierBusiness) 表BusinessHistory(标识符(PK身份),IsActive,日期,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个表,商业和联系。联系人正在更新表插入和更新业务。
业务更新时,它插入到BusinessHistory中,当存储更新的字段IsActive时,该表存储表Business的更新历史记录 。
的事情是,即使我不插入BusinessHistory新行,我启动插入指示等等,我去的,而不是插入的触发器的表BusinessHistory内。当然,在这个结尾,有一个scope_identity()。您只能使用scope_identity一次,并且它会返回插入的最后一个标识。 因此,由于我没有插入任何BusinessHistory,它正在消耗我新插入的联系人的scope_identity:联系人表的插入的 的scope_identity为空!
如何隔离问题?
使用分析器,你搞清楚,有在BusinessHistory插入指令时,它不应该有任何人。
使用调试,你将最终结束在一个INSERT触发器你不应该英寸
如何解决呢?
这里有几种选择。我所做的是由假设条件表业务围绕BusinessHistory的插入: 我想只插入插入如果statut“IsActive”发生了变化:
IF EXISTS
(
SELECT
1
FROM
inserted AS t0
INNER JOIN
deleted AS t1 ON t0.Identifier = t1.Identifier
WHERE
(t0.Identifier <> t1.Identifier)
)
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.Identifier <> t1.Identifier)
END
的另一种可能性是,在触发而不是表BusinessHistory的插入,由IF包围整个触发EXISTS条件
IF EXISTS (SELECT 1 FROM inserted)
BEGIN
----Trigger's code here !
END
如何避免呢?
- 那么,使用这些修复程序之一!
- 在大多数情况下,避免scope_identity(),@@ IDENTITY已经足够了!在我的公司,我们只使用EF_4的scope_identity!
我知道我的英语并不完美,如果它不够好,我可以编辑,或者如果有人想在这个主题上添加一些东西!
哪个'scope_identity()'被插入触发器返回?从看到这个孤立的代码片段中看不清楚。那一刻插入的记录是什么? –
你给了我你的问题的解决方案。在我而不是表B的更新触发器中,我通过插入另一个表来记录表的状态历史记录。 我的错误是插入没有被IF EXISTS包围,第三张表上的插入在错误的时刻消耗了我的scope_identity()。 谢谢,你的帮助:) –
嘿嘿,总是很棘手,这些触发器。也许你可以把它变成答案,这样人们会更容易找到解决方案。 –