September 28, 2014

Entity.GetAttributeValue<T> and ActivityParty

GetAttributeValue<T> is a method of the Entity class, it is used to retrieve easily the entity's values. You can find a detailed overview by Dave Berry here:
Entity.GetAttributeValue Explained

Dynamics CRM includes a special data type called ActivityParty (an overview here) and despite its special status we can still use GetAttributeValue<T> method against the fields using this data type.

First of all the ActivityParty attributes hold an EntityCollection of activityparty entities, these entities are a pointer to the real records through the partyid attribute (EntityReference).
Entity email = service.Retrieve("email", emailId, new ColumnSet(true));
EntityCollection to = email.GetAttributeValue<EntityCollection>("to");
A big difference when using the GetAttributeValue<T> with the EntityCollection than the EntityReference is the case when the attribute is null.

With EntityReference the method GetAttributeValue<T> returns a null if the attribute is empty.
EntityReference parentAccountRef = account.GetAttributeValue<EntityReference>("parentaccountid");
if (parentAccountRef != null) { /* code here */ }
With EntityCollection we can have null if the attribute is not inside the collection or an EntityCollection with no values inside the Entities property if the attribute is empty but inside the attributes list.
The second scenario is very common, for example when retrieving an email, the attributes from,to,cc,bcc are always returned.
Entity email = service.Retrieve("email", emailId, new ColumnSet(true));
EntityCollection to = email.GetAttributeValue<EntityCollection>("to");
EntityCollection cc = email.GetAttributeValue<EntityCollection>("cc");
if (to != null) { Console.WriteLine("Records inside To: " + to.Entities.Count.ToString(); }
if (cc != null) { Console.WriteLine("Records inside Cc: " + cc.Entities.Count.ToString(); }
Even if we have an usable EntityCollection, it's necessary additional code to get the reference to the real records contained inside the ActivityParty attributes.
To simplify the access to the values I created an extension method (called GetEntityReferenceCollectionValue) to return an EntityReferenceCollection from an ActivityParty field:
public static EntityReferenceCollection GetEntityReferenceCollectionValue(
    this Entity entity, string attributeLogicalName)
{
    EntityReferenceCollection entityReferenceCollection = new EntityReferenceCollection();
    EntityCollection entityCollection = entity.GetAttributeValue<EntityCollection>(attributeLogicalName);
    if (entityCollection != null)
    {
        foreach (Entity item in entityCollection.Entities)
        {
            EntityReference partyIdReference = item.GetAttributeValue<EntityReference>("partyid");
            if (partyIdReference != null) { entityReferenceCollection.Add(partyIdReference); }
        }
    }
    return entityReferenceCollection;
}
EntityReferenceCollection is a class that holds a list of EntityReference, it's normally used inside the Associate/Disassociate operations, but nothing stop us to reuse it to hold all the EntityReference entries of an EntityCollection.

The use is straightforward:
Entity email = service.Retrieve("email", emailId, new ColumnSet(true));
EntityReferenceCollection to = email.GetEntityReferenceCollectionValue("to");
If it's necessary to retrieve the actual entities I created a method called GetEntitiesFromEntityReferenceCollection, it requires as parameters the IOrganizationService and the EntityReferenceCollection. The value returned is an IEnumerable<Entity>:
public static IEnumerable<Entity> GetEntitiesFromEntityReferenceCollection(
    IOrganizationService service, EntityReferenceCollection entityReferenceCollection)
{
    List<Entity> entities = new List<Entity>();
    foreach (EntityReference entityReference in entityReferenceCollection)
    {
        try
        {
            Entity entity = service.Retrieve(entityReference.LogicalName, entityReference.Id, new ColumnSet(true));
            entities.Add(entity);
        }
        catch { }
    }
    return entities.AsEnumerable<Entity>();
}
Example:
Entity email = service.Retrieve("email", emailId, new ColumnSet(true));
EntityReferenceCollection to = email.GetEntityReferenceCollectionValue("to");
var toEntities = GetEntitiesFromEntityReferenceCollection(service, to);

1 comment: