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 -
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.
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.