在SQL Server Compact Edition数据库上,如何解决LINQ to SQL中的"找不到或者更改行"异常?

时间:2020-03-05 18:47:59  来源:igfitidea点击:

在使用LINQ to SQL连接更新了几个属性(针对SQL Server Compact Edition)后,对DataContext执行SubmitChanges时,出现"未找到或者更改行"。 ChangeConflictException。

var ctx = new Data.MobileServerDataDataContext(Common.DatabasePath);
var deviceSessionRecord = ctx.Sessions.First(sess => sess.SessionRecId == args.DeviceSessionId);

deviceSessionRecord.IsActive = false;
deviceSessionRecord.Disconnected = DateTime.Now;

ctx.SubmitChanges();

该查询生成以下SQL:

UPDATE [Sessions]
SET [Is_Active] = @p0, [Disconnected] = @p1
WHERE 0 = 1
-- @p0: Input Boolean (Size = 0; Prec = 0; Scale = 0) [False]
-- @p1: Input DateTime (Size = 0; Prec = 0; Scale = 0) [9/4/2008 5:12:02 PM]
-- Context: SqlProvider(SqlCE) Model: AttributedMetaModel Build: 3.5.21022.8

明显的问题是WHERE 0 = 1,加载记录后,我确认" deviceSessionRecord"中的所有属性都正确,可以包含主键。同样,在捕获" ChangeConflictException"时,没有有关此失败原因的其他信息。我还确认了该异常与数据库中的一条记录(我正在尝试更新的记录)一起引发

奇怪的是,我在代码的不同部分中具有非常相似的update语句,并且它生成以下SQL,并且确实更新了SQL Server Compact Edition数据库。

UPDATE [Sessions]
SET [Is_Active] = @p4, [Disconnected] = @p5
WHERE ([Session_RecId] = @p0) AND ([App_RecId] = @p1) AND ([Is_Active] = 1) AND ([Established] = @p2) AND ([Disconnected] IS NULL) AND ([Member_Id] IS NULL) AND ([Company_Id] IS NULL) AND ([Site] IS NULL) AND (NOT ([Is_Device] = 1)) AND ([Machine_Name] = @p3)
-- @p0: Input Guid (Size = 0; Prec = 0; Scale = 0) [0fbbee53-cf4c-4643-9045-e0a284ad131b]
-- @p1: Input Guid (Size = 0; Prec = 0; Scale = 0) [7a174954-dd18-406e-833d-8da650207d3d]
-- @p2: Input DateTime (Size = 0; Prec = 0; Scale = 0) [9/4/2008 5:20:50 PM]
-- @p3: Input String (Size = 0; Prec = 0; Scale = 0) [CWMOBILEDEV]
-- @p4: Input Boolean (Size = 0; Prec = 0; Scale = 0) [False]
-- @p5: Input DateTime (Size = 0; Prec = 0; Scale = 0) [9/4/2008 5:20:52 PM]
-- Context: SqlProvider(SqlCE) Model: AttributedMetaModel Build: 3.5.21022.8

我已经确认在数据库模式和生成LINQ类的DBML中都已经标识了正确的主字段值。

我想这几乎是一个两部分的问题:

  • 为什么会引发异常?
  • 在检查了第二组生成的SQL之后,似乎为了检测冲突,最好检查所有字段,但是我想这会相当低效。这是始终有效的方式吗?是否有仅检查主键的设置?

在过去的两个小时中,我一直在与这个问题作斗争,因此我们将不胜感激。

解决方案

回答

那很讨厌,但是很简单:

检查O / R-Designer中所有字段的数据类型是否与SQL表中的数据类型匹配。
仔细检查是否可为空!列在O / R-Designer和SQL中都应该为空,或者在两者中都不能为空。

例如,NVARCHAR列" title"在数据库中被标记为NULLable,并且包含值NULL。即使在O / R映射中将该列标记为不可为空,LINQ也会成功加载该列并将column-String设置为null。

  • 现在,我们更改某些内容并调用SubmitChanges()。
  • LINQ将生成一个SQL查询,其中包含" WHERE [title] IS NULL",以确保标题未被其他人更改。
  • LINQ在映射中查找[title]的属性。
  • LINQ将发现[title]不可为空。
  • 由于[title]不可为空,因此从逻辑上讲,它永远不可能为NULL!
  • 因此,为优化查询,LINQ将其替换为" where 0 = 1",SQL等效于" never"。

当字段的数据类型与SQL中的数据类型不匹配或者缺少字段时,将出现相同的症状,因为LINQ无法确保自读取数据以来SQL数据没有更改。

回答

我通过将表格从服务器资源管理器重新拖到设计器并重新构建来解决了该错误。

回答

我不知道我们是否对问题找到满意的答案,但我发布了一个类似的问题,最终自己回答了。事实证明,数据库的NOCOUNT默认连接选项已打开,这对于使用Linq对Sql进行的每次更新都会导致ChangeConflictException。我们可以在这里参考我的帖子。

回答

在DataContext上有一个称为Refresh的方法,在这里可能会有所帮助。它允许我们在提交更改之前重新加载数据库记录,并提供不同的模式来确定要保留的值。就我的目的而言," KeepChanges"似乎是最聪明的,它旨在将我的更改与同时发生在数据库中的任何无冲突的更改合并。

如果我理解正确。 :)