我有一个包含数据网格和保存按钮的表单。
当用户单击保存按钮时,我通过检查特定列来检查新行。如果它的值为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
答案 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进行更新,则可能需要考虑绕过它们。