Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

I am using code similar to the following to apply an update to an SPListItem, after necessarily elevating to System privileges on said item.

Because this can be called multiple times for the same item, possibly concurrently, I have a lock from opening the item to updating it. This means concurrent updates do not cause a save conflict, but wait for the previous update to finish.

private static string lockMe = "lockMe";
public static void AffectListItem(SPListItem listItem)
{
    // Elevate
    using (SPSite site = new SPSite(listItem.Web.Site.ID, SPUserToken.SystemAccount))
    {
        using (SPWeb web = site.OpenWeb(listItem.Web.ID))
        {
            SPList list = web.Lists[listItem.ParentList.ID];

            lock(something) // lockMe or listItem, see below
            {
                SPListItem cleanItem = list.GetItemById(listItem.ID);

                // Perform a small server-side update.
                MakeChanges(cleanItem);
                cleanItem.Update();
            }
        }
    }
}

However, I'm not sure exactly what I should be locking on. If I lock on a private, static variable of the class containing this method, then I lock when any items are updated concurrently, not just when the same item is updated twice concurrently. If I lock on listItem, I get no lock at all, because the different listItems are different objects.

Is there something I can lock against that will provide this per-ListItem locking that I need? Alternatively, is this a bad idea, or is there a totally different method of going about it?

share|improve this question
add comment

2 Answers

The lock() statement you are using will only lock that section of your code, and only within the same application domain (ie AppPool. It won't lock across multiple servers in a farm environment). As James said, it will also not lock the list item so that other code cannot update the list item.

As far as I know, for regular list items there isn't a way to lock the record in the way you want to, BUT if the item is a document/file in a document library there is a way. The following code sample will show you how you can lock a file (which will also prevent it's related SPListItem from being modified for the duration of the lock)

      string lockId = "MyLock";
      SPList list = GetList();
      SPListItem item = GetListItem();

      if (list is SPDocumentLibrary)
      {
           //check if the item has a file, and that it is not already locked
           if (item.File != null && item.File.LockType == SPFile.SPLockType.None)
           {
               //lock for exclusive use, for 5 minutes
               item.File.Lock(SPFile.SPLockType.Exclusive, lockId, TimeSpan.FromMinutes(5));
               //ensure the lock is our lock
               if (item.File.LockId == lockId)
               {

                    //do updates here   


                   //make sure we release the lock
                   item.File.ReleaseLock(lockId);
                }
            }
       }

This is a similar mechanism SharePoint uses to lock a document for editing when an file is opened in MS Office for example.

share|improve this answer
    
I'm not worried about other code updating the item - my update is short and frequent, so I'm only really worried about other instances of my update interfering. However, I am now also worried about my code running on different servers, as we are in a multi-server environment. If even a simple lock won't protect against this, I may be better off forgetting about locking and instead working on handling the collisions. –  Rawling Nov 9 '11 at 8:26
    
Just out of interest, although my particular problem isn't with a Document Library so I have no file to lock: does the locking code you give result in wait for lock behaviour like a simple lock statement, or does it result in exception if locked behaviour like normal overlapping updates? –  Rawling Nov 9 '11 at 8:28
    
No it will result in an exception. To reproduce the behaviour, open an office document from a document library and enable editing on that document (without checking out to local). While the document is editable in office, use a browser to try to edit/update the document properties and you should get an error telling you that the document is locked. –  Paul Lucas Nov 9 '11 at 10:22
    
If you are worried about your own code conflicting across multiple servers, what mechanism are you using to trigger the updates to the list items? If it is a SharePoint Timer Job, you can specify the job to use the JobLockType.Job setting to prevent the same job from executing simultaneously on multiple servers. –  Paul Lucas Nov 9 '11 at 10:47
    
The update is driven by the end-user via AJAX and a WebMethod. It's a single-click operation. If two users click at the same time, both updates will ideally occur without one user being presented with a "Someone else updated this item" message. –  Rawling Nov 9 '11 at 13:03
show 4 more comments

Have you tried changing the signature of your MakeChanges method to MakeChanges(ref cleanItem)? Thinking, that the object passed in will be handled differently in memory and the lock might take more effect.

Though, something is telling me that using locks might not be all that affective, as there's nothing stopping another thread, in another assembly, or even another process, opening up an SPListItem to the same item and modifying it.

Have you had any problems to date? SharePoint uses SQL Server locking on the records when performing updates on ListItems anyway.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.