Weird behavior of Post Synchronous ItemUpdated event attached to libraries in SharePoint 2010

This blog post by fellow SharePoint MVP, Randy Williams has always been a good reference for me when working with SharePoint 2007 event receivers. I have decided to test Randy’s finding against SharePoint 2010 and extend his great work by taking into account the newly introduced “Post Synchronous” events.

The following table summarizes how Synchronous, Asynchronous and Post Synchronous events work with lists and libraries in SharePoint 2010.

List BeforePropoerties AfterProperties properties.ListItem
ItemAdding No value New value Null
ItemAdded No value New value New value
ItemAdded – sync No value New value New value
ItemUpdating No value Changed value Original value
ItemUpdated No value Changed value Changed value
ItemUpdated – sync No value Changed value Changed value
ItemDeleting No value No value Original value
ItemDeleted No value No value Null
ItemDeleted – sync No value No value Null

 

Library BeforePropoerties AfterProperties properties.ListItem
ItemAdding No value No value New value
ItemAdded No value No value New value
ItemAdded – sync No value No value New value
ItemUpdating Original value Changed value Original value
ItemUpdated No value No value Changed value
ItemUpdated – sync No value No value Original value
ItemDeleting No value No value Original value
ItemDeleted No value No value Null
ItemDeleted – sync No value No value Null

 

 

No value –> column value in the hash table was not available.
New value –> the new value for the column was available.
Changed value –> the updated value was available.
Original value—> the original value was available.
Null –> the item is not available.

 

As you can see, in the Post Synchronous ItemUpdated event attached to a library ( not a list), the properties.ListItem[“AField”] returns the original value (the value of a field before the update occurs) and there is no way to get the updated value. I’m not sure if this is a bug or by design, I’ll check and get back to you very soon.

Advertisements

Programmatically enforcing relationship behavior for lookup columns in SharePoint 2010

Adding lookup fields programmatically using feature is a common task in SharePoint 2007/2010. Normally, you would create the site column using a Field feature element. However, The lookup field definition requires the Id of the parent list and you have no way to determine this at design time, besides they will be different from one site to another. ( List Instances are different than Site Columns or Content Types; you cannot specify a list instance ID as the case with Site Columns or Content Types).

This dependency will force you to create Lookup columns using code that look up the parent List ID and uses it to create a new field object to define the site column.

I used to do this frequently in SharePoint 2007 but when yesterday when testing that for SharePoint 2010, I just asked myself, how can I programmatically enforce the relationship behavior ?

If you need more info about list relationships in SharePoint 2010, refer to this blog post.

This is straightforward using the UI from the column settings page and fortunately it’s as easy using code.

3

 

Consider the following example, I have two lists :

Parent List –> Employees
Child List –> Projects

I have a “Team Leader” field in the “Projects” list referencing the Employees List to specify the team leader of each project in the “Projects List”. To create a lookup field and enforcing the relationship behavior, see the following code snippet:

string teamLeaderFieldInternalName = projectsList.Fields.AddLookup(“Team Leader”, employeesList.ID, false);
SPFieldLookup teamLeaderField = (SPFieldLookup)projectsList.Fields.GetFieldByInternalName(teamLeaderFieldInternalName);
teamLeaderField.LookupField = employeesList.Fields[“Title”].InternalName;
teamLeaderField.RelationshipDeleteBehavior = SPRelationshipDeleteBehavior.Cascade;
teamLeaderField.Update();

The previous code will raise the following exception “This lookup field cannot enforce a relationship behavior because it is not indexed”. To fix you need to set the Indexed property of teamLeaderField to true as shown below :

string teamLeaderFieldInternalName = projectsList.Fields.AddLookup(“Team Leader”, employeesList.ID, false);
SPFieldLookup teamLeaderField = (SPFieldLookup)projectsList.Fields.GetFieldByInternalName(teamLeaderFieldInternalName);
teamLeaderField.LookupField = employeesList.Fields[“Title”].InternalName;
teamLeaderField.RelationshipDeleteBehavior = SPRelationshipDeleteBehavior.Cascade;
teamleaderField.Indexed = true;
teamLeaderField.Update();

You might also want to check the other members in the SPRelationshipDeleteBehavior Enum, I have copied the members along with their description from MSDN for easier reference below :

None: Nothing happens when a parent item is deleted and the child item is left pointing to the parent as an orphan.

Cascade: A cascade delete happens when deleting a parent item deletes all related children items of the related list.

Restrict: Restricts a parent item having any children items in the related list from being deleted.

Recycling list items using LINQ to SharePoint

Another interesting method that I found while investigating LINQ to SharePoint is the RecycleOnSubmit method.

context.Projects.RecycleOnSubmit(aProject);

context.Projects.DeleteOnSubmit(aProject);

If you want to move an item to the Recycle Bin, use the first method but if you want to entirely delete it use the second one.

And of course don’t forget to call context.SubmitChanges() to commit the changes to the content database.

Recursive and Folder-Scoped LINQ Queries in SharePoint 2010

As you might experienced in SharePoint 2007, a CAML query is by default non recursive. In other words, if you execute a CAML query, you will end up with items from the list root folder. This is still the same in SharePoint 2010. You have to define extra query options as shown below in case you want to query all folders and sub folders within a list (Recursive Query) :

qry.ViewAttributes = “Scope=’Recursive'”;

And if you want to scope your query to a certain folder :

qry.Folder = list.ParentWeb.GetFolder("Folders DocLib/2008");

What about LINQ to SharePoint ?

The default behavior is the same, however if recursive querying is the desired behavior, you can use the ScopeToFolder method from your EntityList<T> object.

Note the following queries:

var q = dc.Projects.Where(p => p.DueDate < DateTime.Now.AddMonths(1));
var q = dc.Projects.ScopeToFolder("", true).Where(p => p.DueDate < DateTime.Now.AddMonths(1));

The first one executes against the list root folder while the second one is recursive. You might be wondering about the empty string that I’m passing to ScopeToFolder method. Well, let’s see what MSDN says about the parameters that the method expects.

public IQueryable<TEntity> ScopeToFolder( string folderUrl, bool recursive )

folderUrl –> The URL of the folder.
recursive –> true to include items in subfolders; false to exclude them.

That’s it, if you want to scope your LINQ query to a specific folder, pass the folder URL as the first parameter to the method & “true” if you want the recursive behavior of the query. In the second query, I just wanted the recursive behavior and I didn’t want to scope my query to any folders so I passed an empty string, this does the trick.

Hope this helps!

Enabling the developer dashboard programmatically in SharePoint 2010

This is a question that I received during the Egyptian community launch of SharePoint 2010 and Office 2010. The following snippet does the trick!

SPWebService contentService = SPWebService.ContentService;
           SPDeveloperDashboardSettings developerDashboard =
             contentService.DeveloperDashboardSettings;
           developerDashboard.DisplayLevel = SPDeveloperDashboardLevel.On;
           developerDashboard.Update();

The guy who asked me this question wanted to create a farm-scoped feature to easily toggle the developer dashboard instead of using Windows PowerShell or STSADM command line utility. He also promised to share his feature with me once he finishes it.

If you cannot wait and you want to do it yourself, it’s very easy thanks to Visual Studio 2010 and the new SharePoint project and item templates that ships with it. Just open up Visual Studio 2010, create an empty SharePoint project, add a farm-scoped feature, add an event receiver to the feature, copy the code above to the FeatureActivated method, deploy your solution and there you go!

130

 

1