Linq to SharePoint UserProfileManager

A client receantly wanted a web part that would display the top 10 most receant hires. There are several ways you can do this. In this case a custom field was created in Shared Service provider that would map a field to Active directory. The field was called, "WhenCreated". Well, the UserProfileManager provides the entry point into the users and their fields you see in SSP. There are some security to consider here. Not every user has access to the UserProfileManager objects. I will save the security setup for my next post. What I want to show you is how Linq is used in SharePoint. I took this idea from the Linq to Sharepoint article. Check it out!

I googled around for LInq to Sharepoint, and most hits were for a SharePoint solution that is up on codeplex. If you are here then i assume you have googled around and found those hits. What that solution seems to do is convert Linq queries to CAML query. Which is not what I wanted. That solution is ideal for querying lists and listItems, which you can do with Linq anyway!! without CAML queries.

So, I'm no Linq expert I just want to show you the simple concept of Linq in SharePoint. It really is no different than any other use you would have for Linq. there is nothing special about Linq in Sharepoint. It works the same way it would with any other object. If you want to learn about Linq, then google around for it. But the main concept is:

1) You can use Linq on any object that implements IEnumerable.

2) You can write Linq Queries to retrieve a subset of the list of objects.

 

In SharePoint I wanted to get a subset of the the UserProfileManager results to only 10 users. The most receant "WhenCreated" users. I also wanted to bind the results to a SPGridView. I will show you that to.

1    private IEnumerable<UserProfile> GetReceantHires() {           
2           ServerContext context = ServerContext.GetContext(SPContext.Current.Site);

3           UserProfileManager allUsers = new UserProfileManager(context);

4           List<UserProfile> fullset = new List<UserProfile>();
5           foreach (UserProfile u in allUsers) {
6                fullset.Add(u);
               
7           }
          
8           return (from user in fullset

                         orderby user["WhenCreated"].Value descending

                          select user).Take(10);
9   }

 

Code Explained: Line 5 - 7: it appears that although userProfileManager implements IEnumerable, I still cant use Linq right on the object. So this is easy enough, I just moved the results to a Generic List of UserProfile.

 

Line 8: this is the full Linq Query. In the case of the client, they had thousand of users. notice that I am able to get query based on a custom field, "WhenCreated".

 

And that's it! right? well, kind of. I now have the subset, but how do I databind ot a SpGridview? well, there are a couple of things to consider here. I am returning a list of IEnumerable. And if I'm going to databind. DataGrids or an SPGridview needs to know about the property you are trying to bind to. But because this is a custom field and is accessed by indexing into it, it doesn't matter if you specify for the SPGridView to bind that field, it simply wount know about it. So here's what you do: (take a look at http://msdn.microsoft.com/en-us/library/bb466219.aspx)

The concept is that you need either a wrapper object that exposes these indexed fields for you or, you put it in a datatable. I did what was easies and copied the code in the MSDN article I already mentioned.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint;
using System.Data;
using System.Web.UI.WebControls;

namespace ReceantHireWebPart
{
    public class PropertyCollectionBinder
    {
        protected DataTable PropertyCollection = new DataTable();
        public PropertyCollectionBinder()
        {
            PropertyCollection.Columns.Add("PropertyName", typeof(string));
            PropertyCollection.Columns.Add("PropertyDepartment", typeof(string));
            PropertyCollection.Columns.Add("PropertyHireDate", typeof(string));
        }
        public void AddProperty(string PropertyName, string PropertyDepartment, string PropertyHireDate)
        {
            DataRow newRow = PropertyCollection.Rows.Add();
            newRow["PropertyName"] = PropertyName;
            newRow["PropertyDepartment"] = PropertyDepartment;
            newRow["PropertyHireDate"] = PropertyHireDate;
        }
        public void BindGrid(SPGridView grid)
        {
            BoundField fldPropertyName = new BoundField();
            fldPropertyName.HeaderText = "Name";
            fldPropertyName.DataField = "PropertyName";
            fldPropertyName.HtmlEncode = false;
            grid.Columns.Add(fldPropertyName);

            SPBoundField fldPropertyValue = new SPBoundField();
            fldPropertyValue.HeaderText = "Department";
            fldPropertyValue.DataField = "PropertyDepartment";
            grid.Columns.Add(fldPropertyValue);

            SPBoundField fldPropertyHire = new SPBoundField();
            fldPropertyHire.HeaderText = "Hire Date";
            fldPropertyHire.DataField = "PropertyHireDate";
            grid.Columns.Add(fldPropertyHire);

            grid.DataSource = PropertyCollection.DefaultView;
            grid.DataBind();
        }

    }
}

 

I basically took the existing code in the MSDN article and adjusted it to databind the columns I wanted. This is the other half of the code: This is where we use the PropertyCollectionBinder Class.

 

protected override void CreateChildControls()
        {

            recUserGrid.AutoGenerateColumns = false;
           
            PropertyCollectionBinder pcb = new PropertyCollectionBinder();

            foreach (UserProfile user in GetReceantHires()) {

->                pcb.AddProperty(string.Format("{0} {1}", user["Firstname"].Value.ToString(), user["Lastname"].Value.ToString()),
                    (user["Department"].Value == null) ? "" : user["Department"].Value.ToString(),
                    ( user["WhenCreated"].Value.ToString());
           
            }
            pcb.BindGrid(recUserGrid);
            Controls.Add(recUserGrid);
           

            base.CreateChildControls();
        }

Code Explained: the code marked with the arrow is where we add the properties. I simply added a condition so at least an empty string goes into the grid if it is null. I just figured if the UserPrifiles I was retrieiving were new, they might not have a Department filled out yet and I did not fill out all the fields in my test environment :)

Conclusion:

  Linq can be used on any object that implements IEnumerable. This includes SharePoint objects!!! DataBinding Linq results is actually quite easy but you need a wrapper object or simply put in a datatable if you want to databind. (if the properites were exposed through intelisense instead of indexing the property, we would not need the wrapper object or datatable).

 

 I my next post I will talk about security, why RunCodewithElevatedPreviledges doesn't always work!! I will go through how to set up so that this web part is viewable to even the basic viewer.

 

Hope this article helps

 

Juan

 

 

Published Tuesday, November 11, 2008 10:25 AM by juanl

Comments

# Creating a Recent Hire WebPart using FullTextSQLQuery object and Linq (Part 1)

Friday, November 28, 2008 5:26 PM by Fringe SharePoint

THE SET UP So I just finished this webpart for a client. I wrote a blog post about how I did this the

# Links (11/30/2008) &laquo; Steve Pietrek - Everything SharePoint

Pingback from  Links (11/30/2008) « Steve Pietrek - Everything SharePoint

# re: Linq to SharePoint UserProfileManager

Monday, December 01, 2008 6:46 AM by SharePoint Hosting Provider

I've been working recently on a project migrating <a href="www.apps4rent.com/.../a> 2001. ... Profiles can be manipulated using the UserProfileManager class found in Microsoft.

Leave a Comment

(required) 
(required) 
(optional)
(required) 
Powered by Community Server (Commercial Edition), by Telligent Systems