Tuesday, May 6, 2025

How to retrieve the names of multi-select options

In Dynamics 365 a multi-select choice field stores its values as an array of integers representing the selected options. I will show 2 methods you can use to retrieve the names of selected options. First is to use WebAPI. And second method is to use OrganizationService.

Method #1: WebAPI

Very straightforward the WebApi request below asks to return all the Case Ids and values of multi-select field Country in each Case:

GET https://myorgxyz.crm.dynamics.com/api/data/v9.2/cases?$select=caseid,new_country

Just make sure to include the following key/value in the request header:

Key: Prefer | Value: odata.include-annotations="OData.Community.Display.V1.FormattedValue"

And here's the sample response body that include the names of selected options

{
    "@odata.context": "https://myorgxyz.crm.dynamics.com/api/data/v9.2/$metadata#cases(caseid,new_country)",
    "value": [
        {
            "@odata.etag": "W/\"15838934\"",
            "caseid": "181b1e7b-ab9b-ef11-8a6a-000d3a15476e",
            "new_country@OData.Community.Display.V1.FormattedValue": "India; Ireland",
            "new_country": "736290021,736290023"
        },
        {
            "@odata.etag": "W/\"14530080\"",
            "caseid": "1a090ac7-7234-ef11-8409-000d3a54d97d",
            "new_country@OData.Community.Display.V1.FormattedValue": "USA; UK",
            "new_country": "736290000,736290051"
        }
    ]
}

Method #2: OrganizationService

I prompted GitHub Copilot chat to give me "Dynamics plugin to get the name of multi select choices". It gave me very good sample code which I massaged a little and turned it into a function for my plugin project:

private string GetMultiChoicesLabel(IOrganizationService service, Entity entity, string multiChoicesLogicalName, ITracingService tracer)
        {
            tracer.Trace("Retrieving selected options for multi-select choice field: " + multiChoicesLogicalName);
            var selectedOptions = (OptionSetValueCollection) entity[multiChoicesLogicalName];
            
            // Retrieve the metadata for the multi-select choice field
            RetrieveAttributeRequest attributeRequest = new RetrieveAttributeRequest
            {
                EntityLogicalName = entity.LogicalName,
                LogicalName = multiChoicesLogicalName,
                RetrieveAsIfPublished = true
            };
            
            RetrieveAttributeResponse attributeResponse = (RetrieveAttributeResponse)service.Execute(attributeRequest);
            MultiSelectPicklistAttributeMetadata metadata = (MultiSelectPicklistAttributeMetadata)attributeResponse.AttributeMetadata;
            
            if (selectedOptions == null)
            {
                tracer.Trace("No Choice selected, returning empty label");
                return string.Empty;
            }
            
            // Map the selected option values to their labels
            var selectedOptionNames = selectedOptions
                .Select(option => metadata.OptionSet.Options.FirstOrDefault(o => o.Value == option.Value)?.Label.UserLocalizedLabel.Label)
                .Where(label => label != null)
                .ToList();
            tracer.Trace("Selected Choices: " + string.Join(", ", selectedOptionNames));
            return string.Join(", ", selectedOptionNames);
        }

So there you have them. With a plugin you can trigger when the field is updated and save the names of selected options in a new field. On the other hand, using the WebAPI method I can pull the names for each record to a table, e.g. Power BI table, so there are readable data/names available to report for instance.