Provisioning SharePoint Lookup Columns

There is alot of misinformation out there in the blogosphere regarding SharePoint Lookup Columns and how to provision them correctly with a Feature.

Let me just say that I’ve tried about every technique I have found, including declaritvely defining the lookup column through CAML schema (field and list definition).  Every technique I have tried (declaritvely) doesn’t work. MSDN references that the <Field> tag can have a List property and that it is the “internal name” of the list. Others say it’s the GUID of the list, while others say it has to all be done in the list schema.

So…as a result, let me give you my two cents on the subject. DON’T declaritvely try to provision a Lookup field. It’s more of a headache than its really worth. In my opinion, the best practice is to do it through a Feature Receiver. You will have complete control over how the lookup field will get created and used. Besides, using a list GUID through XML schema is nonsense, unless you are creating a ListInstance with that GUID (but I’ve tried that too and it doesn’t work).

Go the Feature Receiver route, trust me. There are a few posts out there on various blogs, including a downloadable example on CodePlex. They are all great and will work. However, if you don’t want to bother with those…let me just provide you my technique on provisioning a Lookup column.

First, define a feature that will call a custom Feature Receiver like the following:

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns=http://schemas.microsoft.com/sharepoint/
	Id="6B7DB96E-851B-4790-9A54-6B79DC61C0A7"
	Title="Base Feature"
	Description="Provisions base content types and fields for the site."
	Scope="Site"
	ReceiverAssembly="TSC.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f1710125c5a87ae6"
	ReceiverClass="TSC.SharePoint.BaseFeatureReceiver"
	Hidden="false"
	ImageUrl="TSC/MyFeature.jpg"
	ImageUrlAltText="TSC Custom Feature">
	<ElementManifests>
		<ElementManifest Location="tscfields.xml"/>
		<ElementManifest Location="tscctypes.xml"/>
	</ElementManifests>
</Feature>

Next, create a class in Visual Studio that will inherit SPFeatureReceiver like the following:

public class TSCBaseFeatureReceiver : SPFeatureReceiver
{
    public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        using (SPSite site = (SPSite)properties.Feature.Parent)
        {
              using (SPWeb web = site.RootWeb)
              {
                 // Set lookup columns.
                 SPFieldLookup lookupCol = ProvisionLookupField("MyFieldTitle", "My Field Display Name", "My Site Columns", true, true, SPContext.Current.Site.RootWeb, SPContext.Current.Site.RootWeb.Lists["My List Title"], "Title");
                 LinkToCType(SPContext.Current.Site.RootWeb, "My Content Type", (SPField)lookupCol);
              }
         }
    }

    public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
    {
    }

    public override void FeatureInstalled(SPFeatureReceiverProperties properties)
    {
    }

    public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
    {
    }
}

The last step is to create the methods the code above calls. You can place these methods in the same Feature Receiver below the “FeatureUninstalling” method.

It is important to have your feature first create the lookup column, then to associate the column to a content type. If you look at my Feature XML, you will see that I have an ElementManifest to provision a “tscctypes.xml” file. Within this file, I have defined a few custom content types. You can follow the same process, just change “My Content Type” to the name of the content type you are defining in your Feature.

Now, here are the remaining pieces of code to get this to work:

public static SPFieldLookup ProvisionLookupField(string fieldName, string fieldDisplayName, string group, bool required, bool allowMultipleValues, SPWeb web, SPList lookupList, string lookupField)
{
    web.Fields.AddLookup(fieldName, lookupList.ID, lookupList.ParentWeb.ID, required);
    web.Update();
    SPFieldLookup lookup = (SPFieldLookup)web.Fields.GetFieldByInternalName(fieldName);
    lookup.AllowMultipleValues = allowMultipleValues;
    lookup.LookupField = lookupField;
    lookup.Title = fieldDisplayName;
    lookup.Group = group;
    lookup.Update(true);
    return lookup;
}

public static void LinkToCType(SPWeb web, string contentType, SPField field)
{
    SPContentType ct = web.ContentTypes[contentType];
    ct.FieldLinks.Add(new SPFieldLink(field));
    ct.Update();
}

That’s it!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s