I am often coming to the point that I need to create lookup fields pointing on lists which are also created in the solution.
There are many ways to do it either by using feature receiver or by using the declarative way with xml. Even in the last mentioned way I am often coming to the situation in which it does not work as expected.
Therefore my question what you see what might be the best practices to achieve it. I want to do it the declarative way due to the better maintainability of the solutions.

Some of the mentioned issues are for example that these created site fields are somehow loosing their list references, so that they are not useable in other lists.
(Exception message: <nativehr>0x80070057</nativehr><nativestack></nativestack>)


The first feature I did in the declarative fashion with XML, and that was the last one I did that way. It is ugly and very static in it's definition.

Every other feature afterwards that had to provision lists or libraries were all done in the feature activation code. This way was much better to develop, maintain, and upgrade.

  • I am with you, but my question was how to do it with the best practices in the declarative way. In my solution there are more than 30 content types which might change in later development stages, due to not complete specification. Therefore I need a maintainable approach and I in my opinion many things are pointing on the declarative way. – Husen Sep 25 '15 at 12:41
  • You can't delete or modify columns in content types using the declarative 'ugprade actions' -- you really need to use imperative techniques (code running somewhere) to manage these things in any sort of sane way. – John-M Sep 25 '15 at 13:11
  • If I change the Site Content Type definition which have the Ooverwrite="TRUE"`Atrribute in xml and update afterwards the Solution. The Site Content Types are updated. And if I then read in the SchemaXML from the site content types and update the corresponding List Content types based on the Schema, I only have to make sure that the data within the referenced list are not getting corrupt. Correct my if I am totally wrong in my thinking. For my current testing it works. – Husen Sep 25 '15 at 14:00

Maybe I was a bit too fast in asking this question.
Short after this post I found the Blog Entry: "Lookup fields as site column declarative deployed" of Stefan Bauer.
This entry was exactly what I was searching for. And after simple first testings it showed that it is working.
The secret was the following feature implementation:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
    SPSite targetSite = properties.Feature.Parent as SPSite;

    using (SPSite site = new SPSite(targetSite.ID))
        using (SPWeb web = site.OpenWeb())
            SPField lookupField = web.Fields.TryGetFieldByStaticName("Colors");

            if (lookupField != null)
                // Getting Schema of field
                XDocument fieldSchema = XDocument.Parse(lookupField.SchemaXml);

                // Get the root element of the field definition
                XElement root = fieldSchema.Root;

                // Check if list definition exits exists
                if (root.Attribute("List") != null)
                    // Getting value of list url
                    string listurl = root.Attribute("List").Value;

                    // Get the correct folder for the list
                    SPFolder listFolder = web.GetFolder(listurl);
                    if (listFolder != null && listFolder.Exists == true)
                        // Setting the list id of the schema
                        XAttribute attrList = root.Attribute("List");
                        if (attrList != null)
                            // Replace the url wit the id
                            attrList.Value = listFolder.ParentListId.ToString();

                        // Setting the souce id of the schema
                        XAttribute attrWeb = root.Attribute("SourceID");
                        if (attrWeb != null)
                            // Replace the sourceid with the correct webid
                            attrWeb.Value = web.ID.ToString();

                        // Update field with new schema
                        lookupField.SchemaXml = fieldSchema.ToString();

If code is an option you're better off doing that, but if you're stuck in the sandbox, consider this:

The problem with lookup columns is that they must be deployed after the parent list is deployed, so you can't just throw them in an elements file where all your other fields are defined. Look at the package definition in your solution. The element defining your lookup must be listed after the element definging your parent list, or else the lookup will have no list to bind to when it's deployed, and will be broken.

I blogged about this a few years back with a suggested workaround to deploy your field alongside your list instance.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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