Updating Information Using LINQ to SharePoint Share Point 2010

LINQ provides an efficient, transactional way to update data. Either all modifications made to a given data context are applied or all are rolled back. The update process also supports checking for concurrent updates, allowing for long-running processes to create and hold references to disconnected entity objects without the overhead of maintaining references to heavyweight objects such as SPWeb and SPSite.

Disconnecting Entities
To see disconnected entities in action, let’s add another button to our sample application. Label the button Update and Disconnect, and add the following code:

Notice a few important things in this code. First, a member variable is required to store the updated entities between function calls. Second, it’s important that you disconnect the DataContext object properly. If a logger is attached to the DataContext, the logger must be detached before disposing of the DataContext; otherwise, an error will occur when the entities attempt to reconnect, since the DataContext entity has an internal reference to the logger. This issue may be resolved in the final version of the code.

Reconnecting Entities
Now that we have created some code to update items and disconnect the updated entities, we need some code to reconnect the entities and save the changes. Before we do that, we need to consider error handling for our sample application. Since we have the facility to create disconnected updates, it’s possible that another user will change an item that we have disconnected before our update has been applied. Indeed, even if our update was not performed in a disconnected manner and was made in near real-time, the web-based nature of the SharePoint platform means that it is still likely that data will have changed before the update completes.
As mentioned earlier in this chapter, LINQ to SharePoint provides functionality to deal with this type of error via the Change Conflicts property of the DataContext object. So that we can see the Change Conflicts property in action in our sample application, we need to make a few changes to the user interface:

  1. In the form designer, un-dock the DataGridView from the SplitContainer and add a second SplitContainer in the right pane.
  2. Set the Orientation of this new SplitContainer to Horizontal.
  3. In the top pane of the new SplitContainer, place the original DataGridView control, and again set the Dock property to Fill.
  4. Drag a new, second DataGridView onto the bottom pane of the new SplitContainer.
  5. Again, set the Dock property of this new DataGridView to Fill.

Once you’ve made these changes, add a new button labeled Reconnect and Save. Your updated form should look like this:

Reconnecting Entities

Notice the try/catch block around the Submit Changes statement. You should always define a handler for the Change Conflict Exception since, by its very nature, the exception can occur any time an item is updated. In this sample code, the exception is handled by displaying the resulting conflicts in our user interface. We can use the two new buttons that we added to simulate a disconnected update. First, click the Update and Disconnect button to make updates to a set of records. Using the SharePoint user interface, verify that the updates have not yet been applied to the list. Then go back to the sample application and click Reconnect and Save. This time, checking the SharePoint user interface will confirm that the updates have been applied as expected.

Handling Concurrency Errors when Updating Data

Let’s add another button to our sample application so that we can simulate concurrent updates. Label the button Concurrent Update and add the following code in the on-click event handler:

Notice a few significant aspects of this sample code: First, notice the introduction of the Deferred Loading Enabled property. By default, deferred loading is enabled on a Data Context object. This means that child entities are loaded dynamically if and when they are required. So, for example, our LINQ query returns a collection of Asset Note objects. Each Asset Note object has an Asset Reference property that refers to an OnHireAsset object. Since the OnHire Asset object is not used by the query, it isn’t loaded until it’s required. Our code doesn’t need this property, so to prevent it from being loaded we’ve set Deferred Loading Enabled to false.

Next, a separate Data Context object has been used to simulate a concurrent update, because if we were to use the same Data Context object to attempt a concurrent update, the Data Context object itself would merge the updates internally, resolving the concurrency issue. Internally, the DataContext object uses a dictionary type object known as the EntityTracker to manage all changes that have occurred to entities attached to the DataContext. Attempting to apply concurrent updates to the same DataContext would effectively be handled internally by the Entity Tracker.

By using a second Data Context object, when Submit Changes is called, the changes are committed to the content database. This is significant because each entity implements an interface named ITrack Original Values, and this interface defines an Origina lValues Dictionary object that is used to store the values of each property when the entity is created. A change conflict occurs when the original value for a property does not match the current content database value before an item is updated. By clicking the Concurrent Update button, you’ll see that an error row appears in the lower DataGridView, similar to the illustration. Checking the contents of the Asset Notes list using the SharePoint user interface will confirm that, other than the simulated concurrent update of adding “–Concurrent” to each location code, no other updates have been performed. In effect, the change conflict has aborted any additional changes.

Handling Concurrency Errors when Updating Data

You may be wondering why there is only one row in the Change Conflicts data grid. Earlier, when we covered the properties and methods of the Data Context object, we found that Submit Changes has three overloads. The overload that our sample code uses does not specify a value for Conflict Mode and so the default value of Conflict Mode Fail OnFirst Conflict has been used. This is the reason for us only seeing one conflict. As soon as the first conflict is found, the update is aborted and all changes are rolled back. So that we can see all of the change conflict messages, we can change the SubmitChanges method call to this:


Rerunning the application will now show all the conflicts in the lower Data Grid View. As before, checking the list using the SharePoint user interface will confirm that no changes have actually been made. By setting ConflictMode to Continue On Conflict, we’ve instructed the LINQ to SharePoint provider to attempt all updates before rolling back the changes if any conflicts occurred.

Resolving Change Conflicts

Alerting users to change conflicts would be pretty pointless if there was no way to resolve the conflicts in question. There are a few approaches that we can take when resolving change conflicts.

Resolving Conflicts Globally

The LINQ to SharePoint provider makes resolving conflicts a relatively painless process. The ChangeConflicts property of the DataContext object returns a reference to an object of type Change Conflict Collection. This object provides a ResolveAll method that can be called to resolve all conflicts. What could be simpler? The ResolveAll method has three overloads:

  • Resolve All( ) This overload is used when the default resolution behavior is acceptable. Effectively, this is the same as calling Resolve All with the Refresh Mode parameter set to Keep Changes and the auto Resolve Deletes parameter set to true.
  • Resolve All (RefreshMode) This overload is used when a Refresh Mode setting of Keep Changes is not appropriate.
  • Resolve All (RefreshMode, Boolean) This overload is used when delete conflicts should not be automatically resolved. The Boolean parameter is a flag that determines whether or not to delete conflicts that should be resolved automatically. By allowing delete conflicts to be automatically resolved, any delete conflicts are effectively ignored. This behavior makes sense, because the item to be updated no longer exists, so other than notifying the user, no other options are available. Setting this value to false will cause an InvalidOperationException to be thrown if any delete conflicts exist when Resolve All is called. The ResolveAll methods make use of a Refresh Mode enumeration to specify how conflicts should be resolved. The enumeration has three possible values:
  • KeepChanges When this option is selected for the Refresh Mode parameter of the Resolve All method, any updated values are maintained even if they conflict with the current database values. All other values that were not specifically updated are changed to match the current database values. In effect, this option merges fields that were specifically updated with the latest values in the database.
  • Keep Curren t Values When this option is selected for the Refresh Mode parameter of the ResolveAll method, all field values are applied regardless of whether they match the current database values. In effect, this option disregards all concurrent changes, overwriting them with the current state of the object being updated.
  • OverwriteCurrentValues When this option is selected for the RefreshMode parameter of the ResolveAll method, all field values are updated to reflect thecurrent state of the database. Any updates that do not correspond with the currentstate are lost. This option disregards any changes, replacing all values with thecurrent values from the database.

To see the effects of calling ResolveAll, change the sample code for the Concurrent Update button to this:

You’ll notice that after the ResolveAll method is called, a call to Submi tChanges must again occur to retry the changes. Running the sample application and clicking the Concurrent Update button now returns the same list of change conflicts—but this time each conflict is flagged as resolved. Also, checking the Asset Notes list using the user interface will confirm that all updates have been applied. Try re-running this test to see the operation of the other Refresh Mode options.
Resolving Conflicts Individually I’m sure you’ll agree that the Resolve All method works well when you need to resolve allconflicts en masse, but what happens if you want to apply different rules to some of theconflicts? Or what if you want to apply different rules to specific fields? The LINQ toSharePoint conflict resolution model allows for this behavior.And what if you want to go further? What if you want to handle change conflicts ona field-by-field basis? Again, the LINQ to SharePoint provider allows for this.

Record Level Conflict Resolution Along with a ResolveAll method on theChange Conflict Collection object, which allows you to resolve all conflicts on all objectswith one method call, is a Resolve method on the Object Change Conflict object. Asmentioned earlier, the Objec tChange Conflict object represents a change conflict for asingle entity. Remember that in relational database parlance, an entity corresponds to arecord. By selecting specific Object Change Conflict objects from the Change Conflict Collection,you can apply different resolution options for each record.
For example, if you wanted to ignore any updates where the LocationCode contained Location001, you could change the preceding code sample as follows:

Field Level Conflict Resolution As illustrated in Figure, each Object Change Conflict object has a MemberConflicts property that returns a reference to a collection of Member Change Conflict objects. As described earlier, a Member Change Conflict object represents a change conflict at the individual field level, and again, like the Objec tChange Conflict object, the Member Change Conflict object has a Resolve method. Thedifference this time is that there are only two overloads: The first accepts a RefreshMode parameter and behaves in a similar fashion to the Resolve method on the higher levelobjects. The second override accepts an object, and rather than attempting to resolve theconflict based on the values that have been set, it simply sets the field value to the object.For example, if we wanted to flag fields where new value contained the original valuebut a conflict had been detected, we could do this by appending the text Disputed to thenew field value. Using the preceding code sample, we could achieve this with the following:retry:

You can see that handling change conflicts using LINQ to SharePoint is flexible enough to accommodate practically any requirement.

Considerations when Setting ConflictMode You may have noticed in the past few code samples that Submit Changes is being calledwith Conflict Mode. Continue On Conflict. This is useful when more than one item is being updated, because it allows you to deal with all conflicts at once. Changing this value to Conflict Mode. Fail On First Conflict would allow only one conflict to be detected each time Submit Changes was called. The code in the sample would still work, but it would do so by calling Submit Changes many times, each time resolving one conflict. One thing to bear in mind when resolving conflicts is that in the time it takes to resolve a conflict, more concurrent updates may have occurred. In heavy traffic situations where many concurrent updates present a problem, resolving conflicts individually may be more effective, because it takes less time to apply changes to one item than it does to applychanges to many, so the likelihood of more concurrent updates occurring is reduced.

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Share Point 2010 Topics