C# LINQ-TO-SQL:数据上下文.更改冲突不显示所有冲突

本文关键字:冲突 显示 LINQ-TO-SQL 数据 上下文 | 更新日期: 2023-09-27 17:55:38

我在使用 linq-to-sql 并尝试解决冲突时遇到了问题。问题是有时没有检测到冲突。请查看下面的代码示例:

// Setup the object to re-produce the problem
//
// MyObject has properties: id, my_string, my_int and version (timestamp) to enable
// conflicts detection
var context = new MyDataContext();
var obj = new MyObject();
obj.id = "1";
obj.my_string = "value";
obj.my_int    = 0;
context.MyTable.InsertOnSubmit(obj);
context.SubmitChanges();
context.dispose();
// Get 2 data contexts         
var context1 = new MyDataContext();
var context2 = new MyDataContext();
// Get 2 instances of obj - 1 from each context
var obj1= context1.MyTable.SingleOrDefault(o => o.id == "1");
var obj2= context2.MyTable.SingleOrDefault(o => o.id == "1");
// Change the values of obj1 and update it to the database
obj1.my_string= "value1";
obj1.my_int= 0;
context1.SubmitChanges();
context1.Dispose();
// Update the changes in obj2
obj2.my_string= "value2";
obj2.my_int= 1;
// Now the database contains:
//   id:        "1"
//   my_string: "value1"
//   my_int:    0
// obj2 contains:
//   id:        "1"
//   my_string: "value2"
//   my_int:    1
try
{
  context2.SubmitChanges();
}
catch(ChangeConflictException ex)
{
  LogInfo("Conflicting members:");
  context2.ChangeConflicts[0].MemberConflicts.ToList().ForEach(
                mcc=>LogInfo("Property '{0}': Database value: {1}, Current Value:{2}", mcc.Member.Name, mcc.DatabaseValue, mcc.CurrentValue)
                );
}
context2.Dispose();

在捕获中,我希望看到 3 个成员冲突:my_string、my_int 和版本,但我只看到 2 个成员冲突:my_string 和版本。my_int未被检测为冲突。

如果我在创建对象时将my_int设置为与我分配给 obj2 的值不同的值,则检测到冲突。

我发现了一些共性:当原始对象的属性(任何属性)的值等于 obj1 的值时,不会检测到此属性的冲突。

我想知道如何克服这个问题,以便成功检测到冲突

C# LINQ-TO-SQL:数据上下文.更改冲突不显示所有冲突

我找到了问题的根本原因。我没有为"my_int"属性发生冲突的原因是因为它与 context2"知道"的数据库值不冲突。我将对此进行解释:

我认为冲突被定义为当保存的对象的值不等于数据库中的值时不是!!!

冲突定义为数据库中的当前值不等于上下文熟悉的原始值。原始值是执行选择查询时数据库中的值。

检查我问题中的示例,当 context2 从数据库中选择数据来创建 obj2 时,过程值为:my_string:"值",my_int:0。这些是原始值。

当我尝试保存数据时,LINQ-TO-SQL 将原始值与数据库值进行了比较。此时的数据库值(保存 obj1 之后):my_string:"值 1",my_int:0

结果,我在my_string(原始:"值",数据库:"值1")中没有冲突,但在my_int(原始:0,数据库:0)中没有冲突。

发现这一点帮助我理解为什么没有冲突,但它仍然没有帮助我解决问题,因为错误的值没有保存到数据库中,因为我只分析了 ObjectChangeConflict 中存在的 MemberChangeConflict,如果我正在检查的属性不存在,则跳过检查逻辑。

解决方案是分析可枚举的修改成员,这些成员可以访问所有已修改的属性,对于每个属性,我都可以获得原始值和新值。

若要获取修改后的成员,需要执行一个名为 GetModifiedMembers 的方法。此方法位于对象数据类型的表中,可以按如下方式执行:

 var mmc = context.MyTable.GetModifiedMembers(myobject);

将冲突和修改的成员结合起来,让我完全了解了导致冲突的对象发生了什么,并妥善处理了它。

感谢您Damien_The_Unbeliever在他的评论中给出提示。