开发者

C# LINQ-TO-SQL: datacontext.ChangeConflicts not showing all conflicts

I am running into problem when working with linq-to-sql and trying to resolve conflicts. The problem is that sometimes conflict is not detected. Please look on the below code sample:

// 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(开发者_如何学Python
                mcc=>LogInfo("Property '{0}': Database value: {1}, Current Value:{2}", mcc.Member.Name, mcc.DatabaseValue, mcc.CurrentValue)
                );
}
context2.Dispose();

In the catch I expects to see 3 member conflicts: my_string, my_int and version but I see only 2 member conflicts: my_string and version. The my_int is not detected as conflict.

If I would have setup the my_int when the object was created to value different from the value that I have assigned to obj2, the conflict is being detected.

I found some commonality: when the value of a property (any property) of the original object is equal to the value of obj1, the conflict for this property is not detected.

I would like to get any idea how to overcome this problem so conflicts will successfully detected


I found the root cause for the problem. The reason that I didn't get conflict for "my_int" property is because it is not conflicting with the database value that context2 "knows". I'll explain this:

I thought that conflict is defined as when the values of the object that being saved are not equal to the values in the database. IT'S NOT!!!!

Conflict is defined as when the current value in the database is not equal to the original value that the context familiar. The original value is the value that was in the database when the select query executed.

Examining the example in my question, when context2 selected the data from the database to create obj2, the proeprties values were: my_string: "value", my_int:0. Those are the original values.

When I tried to save the data, LINQ-TO-SQL compared the original values to the database values. The database values at this time (after obj1 was saved): my_string: "value1", my_int:0

As a result, I got conflict in my_string (original: "value", database:"value1") but not in my_int(original: 0, database: 0).

Discovering this helped me to understand why there is no conflict, but still it didn't helped me to solve the problem because the wrong value was not saved to the database because I analyzed only the MemberChangeConflicts that exists in the ObjectChangeConflict and if the property that I am checking is not exists there, the check logic is skipped.

The solution was to analyze also the modified members enumerable that give access to all the properties that were modified and for each one I can get the original value and the new value.

To get the modified members, there is a need to execute method called GetModifiedMembers. This method is in the table of the object data type and can be executed as follows:

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

Combining the conflicts and modified members gave me the full picutre of what happened to the object that caused the conflict and handle it properly.

Thanks for Damien_The_Unbeliever for giving the hint in his comment.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜