System.Data.Linq.ChangeConflictException:未找到或更改行

时间:2009-04-30 08:49:47

标签: c# .net linq

我正在尝试使用LINQ删除选定的gridview行(No 的LinqDataSource)。

更改选择后,将更改detailsview绑定 也。我可以在数据库中添加一个新条目,但是当我添加它时 代码到updatePanel内的删除按钮,我有一个例外:

try
{           
    var query = from i in db.QuestionModules 
                where i.QuestionModuleID == QuestionModuleID 
                select i;

    QuestionModule o = query.First();
    db.QuestionModules.DeleteOnSubmit(o);
    db.SubmitChanges();
}

这是我得到的例外:

System.Data.Linq.ChangeConflictException: Row not found or changed. at
System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode
failureMode) at
System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges() 

我已经有这个问题大约一个星期了,不管我做什么,都是 还在那里,记录不会被删除。

关于该怎么做的任何想法?

19 个答案:

答案 0 :(得分:69)

好的 - 看起来好像(至少在我的情况下)答案是将所有非主键列的UpdateCheck属性设置为DBML文件中的 Never 。这样做立即解决了“未找到或更改行”的问题。

鉴于有传言称微软正在将Linq-To-Sql用于实体框架,有人想知道这些错误是否会被修复?

答案 1 :(得分:51)

您很可能会收到此错误,因为您的某个字段在Linq To SQL设计器和实际数据库中有所不同。

就我而言,这是因为其中一个字段在数据库中可以为空并且在设计器中不可为空,使其在设计器中可以为空并立即解决问题。

答案 2 :(得分:15)

我遇到了同样的问题,遇到了this blog,它基本上表明Linq-To-Sql在乐观并发方面存在问题,其中:

  1. 使用高精度日期时间字段。解决方案是将UpdateCheck设置为永远不会为该列设置DBML文件
  2. 设置为不可见的GridView列正在访问数据对象上的属性(第二个原因没有意义,但它似乎在该博客上风靡一时)。
  3. 我还没有尝试过这些解决方案,但是一旦有了这些解决方案,我会在这里发布。

答案 3 :(得分:14)

我解决了这个问题,确保在更新之前立即刷新我的对象。我使用KeepChanges选项执行此操作。

    db.Refresh(System.Data.Linq.RefreshMode.KeepChanges, employee);

答案 4 :(得分:13)

问题还可能只是表的DBML定义与数据库定义的状态不一致。我刚刚删除了DBML模型并从数据库中再次插入它,它运行起来。

希望这有助于某人。

答案 5 :(得分:6)

似乎也适合我的情况。我正在构建一个内存,从来没有提交过行,它与其他表中的行有几个外键关系。 InsertOnSubmit似乎工作,但后续的DeleteOnSubmit给了我找不到行的错误。我没有填充我提交的行中的每个字段,所以我不知道是否与它有任何关系,但标记所有主表的非主键列消除了错误消息。

还有一个想法:我认为将列的UpdateCheck策略标记为“从不”意味着它不会被用作乐观的可靠性检查的基础。这意味着两个用户可以在任何此类列中写入具有不同数据的给定行,并且不会检测到冲突...意味着提交该行的最后一个用户将覆盖先前用户提交的值。我从各种在线阅读中收集到,对此的一个部分解决方案是在提交之前立即使用Refresh方法来同步任何更改。当然,对行没有任何限制性锁定,无法保证在刷新和提交之间仍然不会更改该行,但在涉及大型数据库的大多数情况下,这种情况很少见。

更新:在进一步审核时,我认为我发现了一个可能影响其他人的情景,所以我想我会分享它以防万一。事实证明,至少我在SQL LINQ中遇到的部分麻烦与触发器有关。看来如果你使用SQL LINQ提交一行并且你的DBA有触发器设计用于将信息写入该行中的某些列,那么SQL LINQ模型将默认“始终”确定自上次写入以来该行已被更改。我提交了部分填充的行,我们的DBA触发器填充了一些列,这样当我尝试进一步修改代码中的行时,它会根据触发器填充的列感知到更改冲突。我现在正在调查处理此问题的最佳方法,但更改这些触发填充字段以使用UpdateCheck策略“When Changed”或“Never”为我工作。希望它有所帮助。

答案 6 :(得分:3)

这只是列定义不匹配的情况。只需从SET @sqlSTR = ' UPDATE ##t SET yourxml.modify(''replace value of (/LabelData/ALT_CODE2/text())[1] with ''''' + @Alt_Code2 + ''''''') WHERE rowId = 1'; EXEC(@sqlSTR) 中删除该表并重新添加即可。请务必更改.dbml以获取具有自动生成数据的列,例如主键或日期时间列。

答案 7 :(得分:2)

更新行时,我有类似的changeconflictexception /“未找到或未更改行”。 通过重新添加dbml中的tabbles来解决它。

答案 8 :(得分:1)

确保相关表中没有列包含null值(即要更新的表)。

答案 9 :(得分:1)

我遇到的问题是我在.net框架中有一个DateTime类型,但是我们的数据库字段是DateTime2类型,这是更高精度的数据类型。因此,当我们提交更改时,对象与数据库的日期字段只有几纳秒,这将导致并发错误。当我们迁移到较新的MSSQL版本并将DateTime字段转换为DateTime2时,就会发生这种情况。

所以在我们的代码中:

    Obj.DateUpdated = DateTime.Now()

我们将其更改为:

    Obj.DateUpdated = DateTime.Parse(DateTime.Now.ToString())

因此,如果在升级和迁移后出现此错误,请检查您的数据类型,尤其是日期字段。

答案 10 :(得分:0)

对我们来说,当我们在SQL Server端切换到DateTime2时,问题就开始了。仅使用Column(DbType =“ DateTime2”)标记字段并没有帮助。 因此,发生的事情是,最初在数据库端,我们将列DateTime2(3)声明为与旧的DateTime类型“向后兼容”,并且一切似乎都正常进行,直到我们注意到当我们使用SQL-2-Linq时,在这些日期字段的更新中获取“找不到行或更改行”异常。简单来说,解决方案是做两件事:

  1. 用[Column(DbType =“ DateTime2(3)”,CanBeNull = false)]以匹配数据库声明。和
  2. 从setter的属性中修剪额外的精度数字,如下所示:

[Column(DbType = "DateTime2(3)", CanBeNull = false)] public DateTime ModifiedAt { get => _modifiedAt; set => _modifiedAt = value.AddTicks(-(value.Ticks % TimeSpan.TicksPerMillisecond)); }

答案 11 :(得分:0)

正如@ dherrin79指出的那样,这可能是由于数据库和代码之间的精确差异造成的。对我来说,问题是数据库列应该是十进制(10,2),但它已被创建为十进制(18,0)。这是一个金钱领域,所以也许我应该使用钱栏类型。

所以,我省了一美元金额,比如3.14美元,但小数被剥去了。这导致数据库值被更改,并且与C#中的值不匹配。

希望这有帮助。

答案 12 :(得分:0)

对我来说,这是一个枚举列(映射到varchar)导致了问题,因此我必须将更新检查传递给never。

答案 13 :(得分:0)

我有类似的问题,虽然删除和重新添加DBML表/类帮助了一些用户,但对我来说有点不同,因为我在客户端使用带有分离实体和ListView的WCF。

如果我使用了.Attach(实体)它失败了 - “找不到或没有找到行” 但是当使用.Attach(实体,原始)时,它每次都有效

public void DeleteTask(Task task)
    {
        TwoDooDataContext db = new TwoDooDataContext();
        db.Tasks.Attach(task,GetTaskByID(task.ID));
        db.Tasks.DeleteOnSubmit(task);
        db.SubmitChanges();
    }

答案 14 :(得分:0)

我只想为可能遇到此问题的人添加我的方案。

我们对Linq to SQL dbml使用自定义T4。我们基本上只修改了原始的字符串属性get / set以自动修剪并设置null。

        get { return _OfficiantNameMiddle.GetValueOrNull(); }
        set 
        {
            value = value.GetValueOrNull();
            if (_OfficiantNameMiddle != value) 
            {
                _IsDirty = true;
                OnOfficiantNameMiddleChanging(value);
                SendPropertyChanging("OfficiantNameMiddle");
                _OfficiantNameMiddle = value;
                SendPropertyChanged("OfficiantNameMiddle");
                OnOfficiantNameMiddleChanged();
            }
        }

我们数据库中的旧数据有一些前导/尾随空格,因此对这些列的任何并发检查都无法导致匹配(它将修剪后的值与非裁剪数据库值进行比较)。分析SQL,抓取SQL并开始注释掉WHERE子句中的项,直到它在并发检查期间开始返回一行,这非常容易。

幸运的是,我们的表中有一个LastUpdatedOn字段,它是通过OnValidate(System.Data.Linq.ChangeAction)自动设置的。

    partial void OnValidate(System.Data.Linq.ChangeAction action)
    {
        if (action == System.Data.Linq.ChangeAction.Insert)
        {
            CreatedBy = CurrentUserID;
            CreatedOn = DateTime.Now;
            LastUpdatedBy = CreatedBy;
            LastUpdatedOn = CreatedOn;
        }
        else if (action == System.Data.Linq.ChangeAction.Update)
        {
            LastUpdatedBy = CurrentUserID;
            LastUpdatedOn = DateTime.Now;
        }
    }

为了绕过这个问题,我们只是在除主键列和LastUpdatedOn列之外的所有列上将并发检查设置为Never。这对我们有用。

答案 15 :(得分:0)

我修复它的方式是:首先我更新数据库,然后我将网格的新值设置为

e.Keys["ColumnOne"] ="new value"
e.Keys["ColumnTwo"] ="new value"

所有这些都是在GridView_RowUpdating事件下完成的。

答案 16 :(得分:0)

此外 - 如果您正在调用linqdatasource的选择方法并手动设置e.result,请确保您还包含任何外键值。

除此之外没有其他任何可行的方法。

答案 17 :(得分:0)

我能够通过在updatepanel回发期间对gridview和datasource执行databind()来解决此问题。

    protected void UpdatePanel1_Load(object sender, EventArgs e)
    {
        GridView1.DataBind();
        LinqDataSource1.DataBind();
    }

每次我的选择索引发生变化时,我都会刷新updatepanel,并且能够解决冲突。

希望这有帮助。

答案 18 :(得分:0)

下:

QuestionModule o = query.First();

您必须添加以下命令:

db.QuestionModule.Attach(o);