In the CRM SDK, when you retrieve the value of an Option Set attribute for an entity, only the integer value is returned. This is true for both early and late binding.
To retrieve the formatted value, i.e. the corresponding string label for the integer value, you would need to use the FormattedValues collection of the entity. For example, if we wanted to get the Preferred Contact Method for an account, this would look like this:
string preferredContactMethodLabel = entity.FormattedValues["preferredcontactmethodcode"];
This approach works for both early and late binding. However, you need to use the attribute’s logical name as a string, which defeats the purpose of early binding.
——————–
Update 17/09/2014: Be aware that in some cases the FormattedValues collection is not populated for the entity, for example for the Target entity of an Update plugin. This is true even if the Option Set field is one of the fields being updated. I have tested this with SP1 installed. The code below has been updated to handle this by returning an empty string. Under these scenarios, you’d need to retrieve the metadata of the field to retrieve the corresponding label.
——————–
To overcome this, I have developed an extension method on the Entity class that allows you to retrieve the formatted value of an Option Set attribute using a lambda. You’d use it like this:
string preferredContactMethodLabel = entity.GetFormattedValue(() => entity.PreferredContactMethodCode);
Just like early binding, the benefit of using a lambda is compiler checking. The lambda is also strongly typed to OptionSetValue, which means doing something like entity.GetOptionSetFormattedValue(() => entity.Name) would result in a compiler error.
public static class EntityExtension { public static string GetFormattedValue(this Entity entity, Expression<Func<OptionSetValue>> optionSetValueExpression) { Func<OptionSetValue> optionSetValueFunc = optionSetValueExpression.Compile(); OptionSetValue optionSetValue = optionSetValueFunc(); if (optionSetValue != null) { var optionSetAttributeName = entity.GetOptionSetAttributeName(optionSetValueExpression); return entity.FormattedValues.ContainsKey(optionSetAttributeName) ? entity.FormattedValues[optionSetAttributeName] : String.Empty; } return null; } public static string GetOptionSetAttributeName(this Entity entity, Expression<Func<OptionSetValue>> optionSetValueExpression) { string expressionString = optionSetValueExpression.ToString(); int lastDotIndex = expressionString.LastIndexOf('.'); string attributeName = lastDotIndex == -1 ? expressionString : expressionString.Substring(lastDotIndex + 1); return attributeName.ToLower(); } }
This approach works base on the convention that the property names of the generated early binding types are the schema names of the entity attributes. Using Expression<Func> allows us to pass and perform string manipulation/interrogation on a lambda that is typed to OptionSetValue.
If the expression () => entity.PreferredContactMethodCode was passed, then optionSetValueExpression.ToString() would give the string below (Harness.Program is my test harness class), which allows us to extract the name of the attribute.
() => value(Harness.Program+<>c__DisplayClass0).entity.PreferredContactMethodCode
So there you have it, with a few simple extension methods you can improve your code quality, reduce chance of error, and keep your early-binding zen ;).