Adding a Value to a Picklist
I have had cause to add values programmatically to a picklist in the contact entity. It is a custom picklist whose values change depending on actions on another entity. I struggled to pull together all the elements that I needed for this solution from areas on the net so I thought I would post this in case anyone faces a similar problem.For a new picklist item you need a string to appear in the dropdown box and an integer that represents the choice in the entity.
This is the code I used:
public void addCourse(string course)
{
if (!inPicklist(course))
{
InsertOptionValueRequest request;
int lastValue = 0;
Option newCourse = new Option();
LocLabel label = new LocLabel();
newCourse.Label = new CrmLabel();
newCourse.Value = new CrmNumber();
foreach (Option o in _picklist.Options)
{
int thisValue = o.Value.Value;
if (thisValue > lastValue) lastValue = thisValue;
}
newCourse.Value.Value = lastValue + 1;
label.Label = course;
newCourse.Label.LocLabels = new LocLabel[] { label };
newCourse.Label.LocLabels[0].LanguageCode = new CrmNumber();
newCourse.Label.LocLabels[0].LanguageCode.Value = 1033;
request = new InsertOptionValueRequest();
request.EntityLogicalName = ENTITYLOGICALNAME;
request.AttributeLogicalName = LOGICALNAME;
request.Label = newCourse.Label;
request.Value = newCourse.Value;
InsertOptionValueResponse response =
(InsertOptionValueResponse)_metadataService.Execute(request);
publishChange();
}
}
The important thing to note is that you cannot edit the picklist directly. It is a concept I forget and struggle with sometimes when working with metadata that it exists in both a published and unpublished state. We use the InsertOptionValueRequest method to alter the picklist, adding an unpublished option to the list. If it were just to stay at that then the value would not appear until the next time someone published the entity, although you could see the value in the entity design screens. For clarity my two constants above that are declared elsewhere in the code are:
ENTITYLOGICALNAME = "contact";
LOGICALNAME="new_course"; //the list I want to change
The very last line of my codeblock then forces the publication of entity.
private void publishChange()
{
CrmService.PublishXmlRequest request =
new CrmService.PublishXmlRequest();
request.ParameterXml = @"<importexportxml>
<entities>
<entity>contact</entity>
</entities>
<nodes>
<securityroles>
<settings>
<workflows>
</importexportxml>";
CrmService.PublishXmlResponse response =
(CrmService.PublishXmlResponse)_crmService.Execute(request);
}
For performance I had put this code into a DLL in the GAC (it contains a library of actions I wanted in a single place) and is called by asynchronous process in a plugin. Having said that the action that fires it will be infrequent and may not actually happen once the system is provisioned and goes live. But either way I hope that I have mitigated any lag when the user clicks the Save button.
Can you provide insight on how to simply retrieve the picklist/optionset label from a query? In CRM 4.0 each class that had picklist attributes contained a property with *Label appended to the name which simply returned the label for the associated value.. why has CRM 2011 done away with this? It appears now the only way to retrieve a label is to pass a picklist value to a function that gets the OptionMetaData for a picklist attribute and iterate over the entire picklist options until you find a matching value and then return that label - a lot more work than should have been necessary.
For example, preferredcontactmethodcode is a built-in option set field for the contact entity.. in CRM 4.0 I could query the contact entity (using LINQ with the XRM.sdk) and there was a preferredcontactmethodcodeLabel property available which displayed the picklist label.. so if a contact record had preferredcontactmethodcode value of 2, preferredcontactmethodcodeLabel was 'E-mail'. With CRM 2011 I can only get the value and it appears I will have to run a 2nd query in order to figure out the label.