Search code examples
dynamics-crmdynamics-crm-2013dynamics-crm-onlinedynamics-crm-2016

Dynamics crm + how to get attribute value based on the type dynamically in plugin code


I have the below requirement.

I need to perform the sum of each field across multiple records of the same entity However while performing the sum, I also need to check the type and cast them accrodingly. For eg, For whole number cast to Int, For Decimal cast to decimal. Also some of the values are aliased value too. I am looking for a generic function which I can call for both alias fields and direct fields and it will return me the value based on the type

Background on the code written below -

  • Attribute List is the list of all attributes that belong to the entity.

Format in which the field values are stored in AttributeList-

AttributeList = { "price ",  "quantity", "contact.revenue", "opportunity.sales"}
  • price, quantity - fields of main entity on which we are querying

  • contact.revenue, opportunity.sales - fields of the aliased entities, entity name is appended to understand which entity's field it is

Below is the code which i have tried so far -

I only have decimal and whole number fields in my attributeList.

private void calculate(List<string> attributeList,List<Entity> mainEntityList,Guid targetId,Guid oppId,Guid contactId)
{

    var mainentity = new mainEntity();
    mainentity.Id = targetId;

    var opportunity = new Opportunity();
    opportunity.Id = oppId;

    var contact = new Contact();
    contact.Id = contactId;


    foreach (var attribute in attributeList)
    {

        var fieldSum = new decimal(0);
        int intFieldSum = 0;
        bool attributeFound = false;

        foreach (var entity in mainEntityList)
        {
            
            if (entity.Contains(attribute))
            {
                var type = entity[attribute].GetType().Name;
                attributeFound = true;

                switch (type)
                    {
                        case "AliasedValue":
                        var aliasedFieldValue = entity.GetAttributeValue<AliasedValue>(attribute);
                        if (aliasedFieldValue.Value.GetType().Name == "Decimal")
                        {
                        decimalFieldSum += (decimal)aliasedFieldValue.Value;
                        }
                        else
                        {
                        intFieldSum += (int)aliasedFieldValue.Value;
                        }
                        break;
                        case "Decimal":
                        decimalFieldSum += entity.GetAttributeValue<decimal>(attribute);
                        break;
                        case "Int32":
                        intFieldSum += entity.GetAttributeValue<int>(attribute);
                        break;
                        default:
                            break;
                    }
            }
        }

        if (attributeFound)
        {
            if (attribute.Contains("opportunity"))
            {
                opportunity[attribute] =  decimalFieldSum != 0 ? decimalFieldSum : intFieldSum; 
            }
            else if (attribute.Contains("contact"))
            {
                contact[attribute] = decimalFieldSum != 0 ? decimalFieldSum : intFieldSum; 
            }
            else
            {
                mainentity[attribute] = decimalFieldSum != 0 ? decimalFieldSum : intFieldSum; 
            }
        }
    }

    service.update(opportunity);
    service.update(contact);
    service.update(mainentity);
}

Any help would be appreciated.


Solution

  • Just a little bit edited your code.

    ...

    var fieldSum = new decimal(0);
    foreach (var entity in mainEntityList)
    {
        fieldSum += GetAttrValue(entity, attribute);
    }
    

    ...

    You can use this function to calculate fieldSum variable which is of decimal type.

    private decimal GetAttrValue(Entity entity, string attribute)
    {
        var attrValue = new decimal(0);
        
        if (!entity.Contains(attribute) || entity.Attributes[attribute] == null)
        {
            return attrValue;
        }
        
        var type = entity.Attributes[attribute].GetType().Name;
        switch (type)
        {
            case "AliasedValue":
                var aliasedFieldValue = entity.GetAttributeValue<AliasedValue>(attribute);
                attrValue = type == "Decimal" ? (decimal)aliasedFieldValue.Value : (int)aliasedFieldValue.Value;
                break;
            case "Decimal":
                attrValue = entity.GetAttributeValue<decimal>(attribute);
                break;
            case "Int32":
                attrValue = entity.GetAttributeValue<int>(attribute);
                break;
            default:
                break;
        }
        return attrValue;
    }
    

    On the other hand if you just need a generic function which will return decimal or int value for an attribute you can use this

    private T GetAttrValue<T>(Entity entity, string attribute)
    {
        if (!entity.Contains(attribute) || entity.Attributes[attribute] == null)
        {
            return default(T);
        }
    
        T result;
        var type = entity.Attributes[attribute].GetType().Name;
        if (type == "AliasedValue")
        {
            var aliasedFieldValue = entity.GetAttributeValue<AliasedValue>(attribute);
            result = (T)aliasedFieldValue.Value;
        }
        else
        {
            result = entity.GetAttributeValue<T>(attribute);
        }
        return result;
    }
    

    --Update--
    So, here is the whole code if I understand you requirements right.
    First of all add this class.

    public class AttributeInfo
    {
        public string Name { get; set; }
    
        public Type Type { get; set; }
    
        public decimal DecimalSum { get; set; } = new decimal(0);
    
        public int IntSum { get; set; } = 0;
    }
    

    And add this function

    private void SetValue(Entity entity, AttributeInfo attributeInfo)
    {
        if (entity.Contains(attributeInfo.Name))
        {
            switch (attributeInfo.Type.Name)
            {
                case "Decimal":
                    entity[attributeInfo.Name] = attributeInfo.DecimalSum;
                    break;
                case "Int32":
                    entity[attributeInfo.Name] = attributeInfo.IntSum;
                    break;
                default:
                    break;
            }
        }
    }
    

    Then this is you Calculate function

    private void Calculate(List<string> attributeList, List<Entity> mainEntityList, Guid targetId, Guid oppId, Guid contactId)
    {
        var mainentity = new mainEntity();
        mainentity.Id = targetId;
    
        var opportunity = new Opportunity();
        opportunity.Id = oppId;
    
        var contact = new Contact();
        contact.Id = contactId;
    
        var attributesInfo = new List<AttributeInfo>();
        foreach (var attribute in attributeList)
        {
            var attributeInfo = new AttributeInfo
            {
                Name = attribute
            };
    
            foreach (var entity in mainEntityList)
            {
                if (entity.Contains(attribute))
                {
                    attributeInfo.Type = entity[attribute].GetType();
                    switch (attributeInfo.Type.Name)
                    {
                        case "AliasedValue":
                            var aliasedFieldValue = entity.GetAttributeValue<AliasedValue>(attribute);
                            if (aliasedFieldValue.Value.GetType().Name == "Decimal")
                            {
                                attributeInfo.DecimalSum += (decimal)aliasedFieldValue.Value;
                            }
                            else
                            {
                                attributeInfo.IntSum += (int)aliasedFieldValue.Value;
                            }
                            break;
                        case "Decimal":
                            attributeInfo.DecimalSum += entity.GetAttributeValue<decimal>(attribute);
                            break;
                        case "Int32":
                            attributeInfo.IntSum += entity.GetAttributeValue<int>(attribute);
                            break;
                        default:
                            break;
                    }
                }
            }
    
            attributesInfo.Add(attributeInfo);
        }
    
        foreach (var attributeInfo in attributesInfo)
        {
            if (attributeInfo.Type != null)
            {
                SetValue(mainentity, attributeInfo);
                SetValue(opportunity, attributeInfo);
                SetValue(contact, attributeInfo);
            }
        }
    
        service.update(mainentity);
        service.update(opportunity);
        service.update(contact);
    }
    

    I should say that the structure of the calculate function still seems weird for me. However, here I tried to keep the main structure.