Fixing ‘The SPListItem being updated was not retrieved with all taxonomy fields’ or how to provision taxonomy fields correctly

If someone wants to provision a taxonomy field in a declarative way, the following pattern should be followed:

      <Field Type="Note" DisplayName="Strategy_0" StaticName="Strategy_0" Name="Strategy_0" ID="{the GUID of your hidden NOTE field here}" ShowInViewForms="FALSE" Required="FALSE" Hidden="TRUE" />
      <Field Type="TaxonomyFieldType" DisplayName="Strategy" ShowField="Term1033" Required="FALSE" EnforceUniqueValues="FALSE" ID="{6f1ce2c9-9c40-407f-a0b9-7785220a14ff}" StaticName="Strategy" Name="Strategy">
        <Customization>
          <ArrayOfProperty>
            <Property>
              <Name>TermSetId</Name>
              <Value xmlns:q2="http://www.w3.org/2001/XMLSchema" p4:type="q2:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">{the GUID of your termset here}</Value>
            </Property>
            <Property>
              <Name>AnchorId</Name>
              <Value xmlns:q3="http://www.w3.org/2001/XMLSchema" p4:type="q3:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">00000000-0000-0000-0000-000000000000</Value>
            </Property>
            <Property>
              <Name>TargetTemplate</Name>
              <Value xmlns:q6="http://www.w3.org/2001/XMLSchema" p4:type="q6:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance"></Value>
            </Property>
            <Property>
              <Name>TextField</Name>
              <Value xmlns:q6="http://www.w3.org/2001/XMLSchema" p4:type="q6:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">{the GUID of your hidden NOTE field here}</Value>
            </Property>
            <Property>
              <Name>IsPathRendered</Name>
              <Value xmlns:q7="http://www.w3.org/2001/XMLSchema" p4:type="q7:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">false</Value>
            </Property>
          </ArrayOfProperty>
        </Customization>
      </Field>

That would be sufficient, if it were not for the SspId property (the GUID of your keyword term store). Unfortunately there is no token for this and SharePoint is not smart enough to use the default one, if you leave it empty! You will get an error ‘The SPListItem being updated was not retrieved with all taxonomy fields‘. So, a little code work-around is needed.

You have to create a feature receiver or something else, which should run the following code against your field:

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            var web = properties.Feature.Parent as SPWeb;

            // Strategy
            var strategyField = web.Lists["YourList"].Fields["YourTaxonomyField"] as TaxonomyField;
            TaxonomyHelper.ConnectTaxonomyField(web.Site, strategyField);
        }
        /// <summary>
        /// Fix up a taxonomy field
        /// </summary>
        /// <param name="site"></param>
        /// <param name="field"></param>
        public static void ConnectTaxonomyField(SPSite site, TaxonomyField field)
        {
            //Create a Taxonomy Session
            TaxonomySession session = new TaxonomySession(site);
            if (session.DefaultKeywordsTermStore != null)
            {
                field.SspId = session.DefaultKeywordsTermStore.Id;
                field.Update();
            }
            else
            {
                throw new Exception(string.Format("DefaultKeyWordTermStore not found in this site {0}", site.Url));
            }
        }

Again, if SharePoint used the default keyword store if you leave out the SspId empty or if there was a token for it, that would not be necessary.

Still, I am happy with the approach, as it is 95% declarative and I need the code only to link my field to the keyword store. The TermsetId is part of my declaration, and not the code, so, goal achieved!

Advertisements