使用LINQ-to-SQL更新行时ChangeConflictException

时间:2011-10-30 03:48:50

标签: c# linq-to-sql

我有一个包含数据网格和保存按钮的表单。

当用户单击保存按钮时,我通过检查特定列来检查新行。如果它的值为0,我将该行插入数据库,如果列值不为0,则更新该行。

我可以正确插入,但在更新异常时:

  

ChangeConflictException未处理,6次更新中的1次失败。

我检查了更新声明,我确定它是正确的。问题是什么,任何人都可以帮助我吗?

int id;
for (int i = 0; i < dgvInstructores.Rows.Count - 1; i++)
{
    id = int.Parse(dgvInstructores.Rows[i].Cells["ID"].Value.toString());
    if (id == 0)
    {
        dataClass.procInsertInstructores(name, nationalNum, tel1, tel2, 
                                            address, email);
        dataClass.SubmitChanges();
    }
    else
    {
        dataClass.procUpdateInstructores(id, name, nationalNum, tel1, tel2, 
                                            address, email);
        dataClass.SubmitChanges();
    }
}

我正在使用linq来查询sql server2005数据库和vs2008

'procUpdateInstructores'的存储过程是:

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go

ALTER proc [dbo].[procUpdateInstructores]
@ID int,
@name varchar(255),
@NationalNum varchar(25),
@tel1 varchar(15),
@tel2 varchar(15),
@address varchar(255),
@email varchar(255)
as
begin

BEGIN TRANSACTION

update dbo.Instructores
set
Name = @name , NationalNum = @NationalNum ,
tel1 = @tel1 , tel2 = @tel2 , address = @address , email = @email
where ID = @ID

IF (@@ROWCOUNT > 0) AND (@@ERROR = 0)
     BEGIN
          COMMIT TRANSACTION
     END
ELSE
     BEGIN
          ROLLBACK TRANSACTION
     END
end

3 个答案:

答案 0 :(得分:0)

如果没有进一步的信息(您的SQL或C#更新代码看起来像......),我的第一个建议是在for循环之外进行一次SubmitChanges,而不是每行提交一次更改。

答案 1 :(得分:0)

根据我的经验,(使用.net表单和使用linq-to-sql的mvc)我发现如果表单集合包含数据对象的ID参数,那么更新肯定会失败。

即使ID是实际ID,当您绑定它或更新它或分配给另一个变量时,它仍然被标记为'propertyChanged'。

因此,我们可以看到存储过程的代码吗?更具体地说,更新proc?

您上面发布的代码很好,例外应来自您的存储过程。

但是,如果您确信proc是正确的,那么可能会查看用于生成表的HTML代码。对于ID列等的0/1,可能存在一些错误。

答案 2 :(得分:0)

在这种情况下,您正在使用DataGridView(因此WinForms)。我进一步猜测你的dataClass是持久保存在表单上的,这样你就可以从你试图保存更改的同一个dataClass中加载和绑定DataGridView。

假设您正在将DataGridView数据绑定到通过LINQ to SQL返回的实体,当您编辑这些值时,您正在标记有问题的实体在调用下一个SubmitChanges时需要更新它。

在您的更新中,您正在调用dataClass.procUpdateInstructores(id, name, nationalNum, tel1, tel2, address, email);,它会立即针对数据库发出存储过程,并在编辑时设置新值。下一行是踢球者。由于您的数据上下文仍然认为该对象仍然是脏的,因此SubmitChanges尝试使用它作为Where子句的一部分获取的原始值(以检查并发性)向您的数据库发送另一个更新语句。由于存储过程更新了这些值,因此Where子句无法找到匹配值,从而返回并发异常。

在这种情况下,最好的办法是修改LINQ to SQL模型,以使用存储过程进行更新和插入,而不是运行时生成的版本。然后在解析代码中,只需调用SubmitChanges而无需手动调用procUpdateInstructores。如果正确配置了dbml,它将调用存储的proc而不是动态更新语句。

另外,FWIW,你的存储过程似乎没有做任何比生成的SQL更多的事情。实际上,LINQ to SQL会为您提供更多功能,因为您还没有在存储过程中进行任何并发检查。如果您需要使用DBA或某些安全策略来存储过程,您可以保留它们,但如果这是您的所有存储过程正在执行并依赖于运行时生成的SQL进行更新,则可能需要考虑绕过它们。