/// <summary> /// Handle general related entity collection construction /// </summary> /// <param name="rootExpando">Object being added too</param> /// <param name="entityName">parent entity</param> /// <param name="entityCollection">collection of relationships</param> /// <param name="mUtil">meta-data utility</param> /// <returns></returns> internal static ExpandoObject ReleatedEntitiesToExpandoObject(ExpandoObject rootExpando, string entityName, RelatedEntityCollection entityCollection, MetadataUtility mUtil) { if (rootExpando == null) { return(rootExpando); } if (entityCollection != null && entityCollection.Count == 0) { // nothing to do, just return. return(rootExpando); } foreach (var entItem in entityCollection) { string key = ""; bool isArrayRequired = false; dynamic expando = new ExpandoObject(); var expandoObject = (IDictionary <string, object>)expando; ExpandoObject childEntities = new ExpandoObject(); List <ExpandoObject> childCollection = new List <ExpandoObject>(); // Get the Entity relationship key and entity and reverse it back to the entity key name var eData = mUtil.GetEntityMetadata(Xrm.Sdk.Metadata.EntityFilters.Relationships, entItem.Value.Entities[0].LogicalName); // Find the relationship that is referenced. var ERM21 = eData.ManyToOneRelationships.FirstOrDefault(w1 => w1.SchemaName.ToLower().Equals(entItem.Key.SchemaName.ToLower())); var ERM2M = eData.ManyToManyRelationships.FirstOrDefault(w2 => w2.SchemaName.ToLower().Equals(entItem.Key.SchemaName.ToLower())); var ER12M = eData.OneToManyRelationships.FirstOrDefault(w3 => w3.SchemaName.ToLower().Equals(entItem.Key.SchemaName.ToLower())); // Determine which one hit if (ERM21 != null) { isArrayRequired = true; key = ERM21.ReferencedEntityNavigationPropertyName; } else if (ERM2M != null) { isArrayRequired = true; if (ERM2M.Entity1LogicalName.ToLower().Equals(entityName)) { key = ERM2M.Entity1NavigationPropertyName; } else { key = ERM2M.Entity2NavigationPropertyName; } } else if (ER12M != null) { key = ER12M.ReferencingAttribute; } if (string.IsNullOrEmpty(key)) // Failed to find key { throw new DataverseOperationException($"Relationship key {entItem.Key.SchemaName} cannot be found for related entities of {entityName}."); } foreach (var ent in entItem.Value.Entities) { // Check to see if the entity itself has related entities if (ent.RelatedEntities != null && ent.RelatedEntities.Count > 0) { childEntities = ReleatedEntitiesToExpandoObject(childEntities, entityName, ent.RelatedEntities, mUtil); } // generate object. ExpandoObject ent1 = ToExpandoObject(ent, mUtil); if (((IDictionary <string, object>)childEntities).Count() > 0) { foreach (var item in (IDictionary <string, object>)childEntities) { ((IDictionary <string, object>)ent1).Add(item.Key, item.Value); } } childCollection?.Add((ExpandoObject)ent1); } if (childCollection.Count == 1 && isArrayRequired == false) { ((IDictionary <string, object>)rootExpando).Add(key, childCollection[0]); } else { ((IDictionary <string, object>)rootExpando).Add(key, childCollection); } } return(rootExpando); }
/// <summary> /// Parses an attribute array into a object that can be used to create a JSON request. /// </summary> /// <param name="sourceEntity">Entity to process</param> /// <param name="mUtil"></param> /// <returns></returns> internal static ExpandoObject ToExpandoObject(Entity sourceEntity, MetadataUtility mUtil) { dynamic expando = new ExpandoObject(); // Check for primary Id info: if (sourceEntity.Id != Guid.Empty) { sourceEntity = UpdateEntityAttributesForPrimaryId(sourceEntity, mUtil); } AttributeCollection entityAttributes = sourceEntity.Attributes; if (!(entityAttributes != null) && (entityAttributes.Count > 0)) { return(expando); } var expandoObject = (IDictionary <string, object>)expando; var attributes = entityAttributes.ToArray(); // this is used to support ActivityParties collections List <ExpandoObject> partiesCollection = null; foreach (var attrib in entityAttributes) { var keyValuePair = attrib; var value = keyValuePair.Value; var key = keyValuePair.Key; if (value is EntityReference entityReference) { var attributeInfo = mUtil.GetAttributeMetadata(sourceEntity.LogicalName, key.ToLower()); // Get Lookup attribute meta data for the ER to check for polymorphic relationship. if (attributeInfo is Xrm.Sdk.Metadata.LookupAttributeMetadata attribData) { // Now get relationship to make sure we use the correct name. var eData = mUtil.GetEntityMetadata(Xrm.Sdk.Metadata.EntityFilters.Relationships, sourceEntity.LogicalName); var ERNavName = eData.ManyToOneRelationships.FirstOrDefault(w => w.ReferencingAttribute.Equals(attribData.LogicalName) && w.ReferencedEntity.Equals(entityReference.LogicalName)) ?.ReferencingEntityNavigationPropertyName; if (!string.IsNullOrEmpty(ERNavName)) { key = ERNavName; } // Populate Key property key = $"{key}@odata.bind"; } else if (attributeInfo == null) { // Fault here. throw new DataverseOperationException($"Entity Reference {key.ToLower()} was not found for entity {sourceEntity.LogicalName}.", null); } string entityReferanceValue = string.Empty; // process ER Value if (entityReference.KeyAttributes?.Any() == true) { entityReferanceValue = ParseAltKeyCollection(entityReference.KeyAttributes); } else { entityReferanceValue = entityReference.Id.ToString(); } value = $"/{mUtil.GetEntityMetadata(Xrm.Sdk.Metadata.EntityFilters.Entity, entityReference.LogicalName).EntitySetName}({entityReferanceValue})"; } else { if (value is EntityCollection) { // try to get the participation type id from the key. int PartyTypeId = PartyListHelper.GetParticipationtypeMasks(key); bool isActivityParty = PartyTypeId != -1; // if the partytypeID is -1 this is not a activity party collection. if (isActivityParty && partiesCollection == null) { partiesCollection = new List <ExpandoObject>(); // Only build it when needed. } // build linked collection here. foreach (var ent in (value as EntityCollection).Entities) { ExpandoObject rslt = ToExpandoObject(ent, mUtil); if (isActivityParty) { var tempDict = ((IDictionary <string, object>)rslt); tempDict.Add("participationtypemask", PartyTypeId); partiesCollection.Add((ExpandoObject)tempDict); } } if (isActivityParty) { continue; } // Note.. if this is not an activity party but instead an embedded entity.. this will fall though and fail with trying to embed an entity. } else { key = key.ToLower(); if (value is OptionSetValueCollection optionSetValues) { string mselectValueString = string.Empty; foreach (var opt in optionSetValues) { mselectValueString += $"{opt.Value.ToString()},"; } value = mselectValueString.Remove(mselectValueString.Length - 1); } else if (value is OptionSetValue optionSetValue) { value = optionSetValue.Value.ToString(); } else if (value is DateTime dateTimeValue) { var attributeInfo = mUtil.GetAttributeMetadata(sourceEntity.LogicalName, key.ToLower()); if (attributeInfo is Xrm.Sdk.Metadata.DateTimeAttributeMetadata attribDateTimeData) { if (attribDateTimeData.DateTimeBehavior == Xrm.Sdk.Metadata.DateTimeBehavior.DateOnly) { value = dateTimeValue.ToUniversalTime().ToString("yyyy-MM-dd"); } else { if (attribDateTimeData.DateTimeBehavior == Xrm.Sdk.Metadata.DateTimeBehavior.TimeZoneIndependent) { value = dateTimeValue.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fff"); } else { if (attribDateTimeData.DateTimeBehavior == Xrm.Sdk.Metadata.DateTimeBehavior.UserLocal) { value = dateTimeValue.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); } } } } } else if (value is Money moneyValue) { value = moneyValue.Value; } else if (value is bool boolValue) { value = boolValue.ToString(); } else if (value is Guid guidValue) { value = guidValue.ToString(); } else if (value is null) { var attributeInfo = mUtil.GetAttributeMetadata(sourceEntity.LogicalName, key.ToLower()); if (attributeInfo is Xrm.Sdk.Metadata.LookupAttributeMetadata attribData) { // Populate Key property key = $"{key}@odata.bind"; } value = null; } } } expandoObject.Add(key, value); } // Check to see if this contained an activity party if (partiesCollection?.Count > 0) { expandoObject.Add($"{sourceEntity.LogicalName}_activity_parties", partiesCollection); } return((ExpandoObject)expandoObject); }
/// <summary> /// checks to see if an attribute has been added to the collection containing the ID of the entity . /// this is required for the WebAPI to properly function. /// </summary> /// <param name="sourceEntity"></param> /// <param name="mUtil"></param> /// <returns></returns> private static Entity UpdateEntityAttributesForPrimaryId(Entity sourceEntity, MetadataUtility mUtil) { if (sourceEntity.Id != Guid.Empty) { var entMeta = mUtil.GetEntityMetadata(sourceEntity.LogicalName); sourceEntity.Attributes[entMeta.PrimaryIdAttribute] = sourceEntity.Id; } return(sourceEntity); }
public DynamicEntityUtility(ServiceClient svcActions, MetadataUtility metaUtility) { svcAct = svcActions; metadataUtil = metaUtility; }