Sunday, March 17, 2013

Client Object Model List.GetItemById May Cause "Version Conflict"

 
I was using SharePoint Client Object Model to update list items in a while loop from client side. I noticed that "Version Conflict" will be thrown when updating a list item. After a few tries, I noticed that next pattern will cause the "Version Conflict".
 
1. Get list item by query. Update item.
2. Get list item by ID. Update item.
3. Get list item by query. UPdate item.
4. Get list item by ID. Update item.
 
The last step will cause "Version conflict". After using "Fiddler" to monitor the requests and using "Reflector" to read the code behind "List.GetItemById", my conclusion is that the "List.GetItemById" may cache the list item, and after step 3, the cached list item is not valid any more.
using (ClientContext context = new ClientContext(tbUrl.Text))
{
try

{
Web web = context.Site.OpenWebById(currListInfo.WebId);
List list = web.Lists.GetById(currListInfo.ListId);
string queryTxt = "<View><Query><Where><Contains><FieldRef Name=\"Title\" /><Value Type=\"Text\">Test</Value></Contains></Where></Query></View>";
CamlQuery query = new CamlQuery();
query.ViewXml = queryTxt;

// 1st update
ListItemCollection items = list.GetItems(query);
context.Load(items);
context.ExecuteQuery();
ListItem item = items[0];
string old = item["Content"] as string;
item["Content"] = DateTime.Now.ToString() + " 1 " + old + "<br />";
item.Update();
context.ExecuteQuery();
// 2nd update
item = list.GetItemById(158);
item["Content"] = DateTime.Now.ToString() + " 2 " + old + "<br />";
item.Update();
context.ExecuteQuery();



// 3rd update
items = list.GetItems(query);
context.Load(items);
context.ExecuteQuery();
item = items[0];
item["Content"] = DateTime.Now.ToString() + " 1 " + old + "<br />";
item.Update();
context.ExecuteQuery();
//4th update
item = list.GetItemById(158);
item["Content"] = DateTime.Now.ToString() + " 3 " + old + "<br />";
item.Update();
context.ExecuteQuery();
}
catch (Exception expt)
{
LogInfo(expt.Message + expt.StackTrace);
}
}
The solution is to try to avoid using List.GetItemById if possible.
 
In another scenario, next pattern will also cause "Version conflict".
 
1. Get list item by query. Update list item.
2. Some operation changed the list item.
3. Update list item.
 
Since the step 3 don't get the list item by query again, the old list item has been invalid by step 2. In this case, the step 3 must query the list again to get the list item. However try to avoid using List.GetItemById since this will cause the pattern discussed previously.
 
For example
while (true)
{
1. Get list item by query. Update list item.
2. Some operation changed the list item.
3. Get list item by List.GetItemById. Update list item. (cached list item causes "version conflict" after the first loop.
}
 
This will result in the invalid cached list item after the first loop.

No comments:

Post a Comment