更新其他表时,EF4 RowCount问题而不是插入触发器

时间:2017-06-08 13:42:15

标签: sql-server triggers entity-framework-4 rowcount

我在使用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)

我知道我的更新代码完全有效,因为手动插入可以完成工作。只有在我使用实体框架时才会出现问题。

1 个答案:

答案 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

如何避免?

  • 好吧,使用其中一个修复程序!
  • 在大多数情况下,避免使用scope_identity(),@ @ IDENTITY已经绰绰有余了!在我公司,我们只使用scope_identity因为EF 4!

我知道我的英语不完美,如果不够好我可以编辑,或者有人想在这个主题上添加一些内容!