public static Entity ProjectAttributes(this Entity e, QueryExpression qe, XrmFakedContext context) { if (qe.ColumnSet == null) { return(e); } if (qe.ColumnSet.AllColumns) { return(e); //return all the original attributes } else { //Return selected list of attributes in a projected entity Entity projected = null; //However, if we are using proxy types, we must create a instance of the appropiate class if (context.ProxyTypesAssembly != null) { var subClassType = context.FindReflectedType(e.LogicalName); if (subClassType != null) { var instance = Activator.CreateInstance(subClassType); projected = (Entity)instance; projected.Id = e.Id; } else { projected = new Entity(e.LogicalName) { Id = e.Id } }; //fallback to generic type if type not found } else { projected = new Entity(e.LogicalName) { Id = e.Id } }; foreach (var attKey in qe.ColumnSet.Columns) { //Check if attribute really exists in metadata if (!context.AttributeExistsInMetadata(e.LogicalName, attKey)) { OrganizationServiceFaultQueryBuilderNoAttributeException.Throw(attKey); } if (e.Attributes.ContainsKey(attKey) && e.Attributes[attKey] != null) { projected[attKey] = CloneAttribute(e[attKey]); } } //Plus attributes from joins foreach (var le in qe.LinkEntities) { ProjectAttributes(e, projected, le, context); } //foreach (var attKey in e.Attributes.Keys) //{ // if(e[attKey] is AliasedValue && !projected.Attributes.ContainsKey(attKey)) // projected[attKey] = e[attKey]; //} return(projected); } }
public static object GetConditionExpressionValueCast(string value, XrmFakedContext ctx, string sEntityName, string sAttributeName) { if (ctx.ProxyTypesAssembly != null) { //We have proxy types so get appropiate type value based on entity name and attribute type var reflectedType = ctx.FindReflectedType(sEntityName); if (reflectedType != null) { var attributeType = ctx.FindReflectedAttributeType(reflectedType, sAttributeName); if (attributeType != null) { try { return(GetValueBasedOnType(attributeType, value)); } catch (Exception e) { throw new Exception(string.Format("When trying to parse value for entity {0} and attribute {1}: {2}", sEntityName, sAttributeName, e.Message)); } } } } //Try parsing a guid Guid gOut = Guid.Empty; if (Guid.TryParse(value, out gOut)) { return(gOut); } //Try checking if it is a numeric value, cause, from the fetchxml it //would be impossible to know the real typed based on the string value only // ex: "123" might compared as a string, or, as an int, it will depend on the attribute // data type, therefore, in this case we do need to use proxy types bool bIsNumeric = false; bool bIsDateTime = false; double dblValue = 0.0; decimal decValue = 0.0m; int intValue = 0; if (double.TryParse(value, out dblValue)) { bIsNumeric = true; } if (decimal.TryParse(value, out decValue)) { bIsNumeric = true; } if (int.TryParse(value, out intValue)) { bIsNumeric = true; } DateTime dtValue = DateTime.MinValue; if (DateTime.TryParse(value, out dtValue)) { bIsDateTime = true; } if (bIsNumeric || bIsDateTime) { throw new Exception("When using arithmetic values in Fetch a ProxyTypesAssembly must be used in order to know which types to cast values to."); } //Default value return(value); }
public OrganizationResponse Execute(OrganizationRequest request, XrmFakedContext ctx) { var req = request as InitializeFromRequest; if (req == null) { throw new FaultException <OrganizationServiceFault>(new OrganizationServiceFault(), "Cannot execute InitializeFromRequest without the request"); } //TODO: Implement logic to filter mapping attributes based on the req.TargetFieldType if (req.TargetFieldType != TargetFieldType.All) { throw PullRequestException.PartiallyNotImplementedOrganizationRequest(req.GetType(), "logic for filtering attributes based on TargetFieldType other than All is missing"); } var service = ctx.GetOrganizationService(); var fetchXml = string.Format(FetchMappingsByEntity, req.EntityMoniker.LogicalName, req.TargetEntityName); var mapping = service.RetrieveMultiple(new FetchExpression(fetchXml)); var sourceAttributes = mapping.Entities.Select(a => a.GetAttributeValue <AliasedValue>("attributemap.sourceattributename").Value.ToString()).ToArray(); var columnSet = sourceAttributes.Length == 0 ? new ColumnSet(true) : new ColumnSet(sourceAttributes); var source = service.Retrieve(req.EntityMoniker.LogicalName, req.EntityMoniker.Id, columnSet); // If we are using proxy types, and the appropriate proxy type is found in // the assembly create an instance of the appropiate class // Othersise return a simple Entity Entity entity = new Entity { LogicalName = req.TargetEntityName, Id = Guid.Empty }; if (ctx.ProxyTypesAssembly != null) { var subClassType = ctx.FindReflectedType(req.TargetEntityName); if (subClassType != null) { var instance = Activator.CreateInstance(subClassType); entity = (Entity)instance; } } if (mapping.Entities.Count > 0) { foreach (var attr in source.Attributes) { var mappingEntity = mapping.Entities.FirstOrDefault(e => e.GetAttributeValue <AliasedValue>("attributemap.sourceattributename").Value.ToString() == attr.Key); if (mappingEntity == null) { continue; } var targetAttribute = mappingEntity.GetAttributeValue <AliasedValue>("attributemap.targetattributename").Value.ToString(); entity[targetAttribute] = attr.Value; var isEntityReference = string.Equals(attr.Key, source.LogicalName + "id", StringComparison.CurrentCultureIgnoreCase); if (isEntityReference) { entity[targetAttribute] = new EntityReference(source.LogicalName, (Guid)attr.Value); } else { entity[targetAttribute] = attr.Value; } } } var response = new InitializeFromResponse { Results = { ["Entity"] = entity } }; return(response); }
public static Entity ProjectAttributes(this Entity e, QueryExpression qe, XrmFakedContext context) { if (qe.ColumnSet == null || qe.ColumnSet.AllColumns) { return(RemoveNullAttributes(e)); //return all the original attributes } else { //Return selected list of attributes in a projected entity Entity projected = null; //However, if we are using proxy types, we must create a instance of the appropiate class if (context.ProxyTypesAssembly != null) { var subClassType = context.FindReflectedType(e.LogicalName); if (subClassType != null) { var instance = Activator.CreateInstance(subClassType); projected = (Entity)instance; projected.Id = e.Id; } else { projected = new Entity(e.LogicalName) { Id = e.Id } }; //fallback to generic type if type not found } else { projected = new Entity(e.LogicalName) { Id = e.Id } }; foreach (var attKey in qe.ColumnSet.Columns) { //Check if attribute really exists in metadata if (!context.AttributeExistsInMetadata(e.LogicalName, attKey)) { FakeOrganizationServiceFault.Throw(ErrorCodes.QueryBuilderNoAttribute, string.Format("The attribute {0} does not exist on this entity.", attKey)); } if (e.Attributes.ContainsKey(attKey) && e.Attributes[attKey] != null) { projected[attKey] = CloneAttribute(e[attKey], context); string formattedValue = ""; if (e.FormattedValues.TryGetValue(attKey, out formattedValue)) { projected.FormattedValues[attKey] = formattedValue; } } } //Plus attributes from joins foreach (var le in qe.LinkEntities) { ProjectAttributes(RemoveNullAttributes(e), projected, le, context); } return(RemoveNullAttributes(projected)); } }
public OrganizationResponse Execute(OrganizationRequest req, XrmFakedContext context) { var request = req as RetrieveRequest; if (request.Target == null) { throw new ArgumentNullException("Target", "RetrieveRequest without Target is invalid."); } var entityName = request.Target.LogicalName; var columnSet = request.ColumnSet; if (columnSet == null) { throw new FaultException <OrganizationServiceFault>(new OrganizationServiceFault(), "Required field 'ColumnSet' is missing"); } var id = context.GetRecordUniqueId(request.Target); //Entity logical name exists, so , check if the requested entity exists if (context.Data.ContainsKey(entityName) && context.Data[entityName] != null && context.Data[entityName].ContainsKey(id)) { //Return the subset of columns requested only var reflectedType = context.FindReflectedType(entityName); //Entity found => return only the subset of columns specified or all of them var resultEntity = context.Data[entityName][id].Clone(reflectedType, context); if (!columnSet.AllColumns) { resultEntity = resultEntity.ProjectAttributes(columnSet, context); } resultEntity.ApplyDateBehaviour(context); if (request.RelatedEntitiesQuery != null && request.RelatedEntitiesQuery.Count > 0) { foreach (var relatedEntitiesQuery in request.RelatedEntitiesQuery) { if (relatedEntitiesQuery.Value == null) { throw new ArgumentNullException("relateEntitiesQuery.Value", string.Format("RelatedEntitiesQuery for \"{0}\" does not contain a Query Expression.", relatedEntitiesQuery.Key.SchemaName)); } var fakeRelationship = context.GetRelationship(relatedEntitiesQuery.Key.SchemaName); if (fakeRelationship == null) { throw new Exception(string.Format("Relationship \"{0}\" does not exist in the metadata cache.", relatedEntitiesQuery.Key.SchemaName)); } var relatedEntitiesQueryValue = (QueryExpression)relatedEntitiesQuery.Value; QueryExpression retrieveRelatedEntitiesQuery = relatedEntitiesQueryValue.Clone(); if (fakeRelationship.RelationshipType == XrmFakedRelationship.enmFakeRelationshipType.OneToMany) { var isFrom1to2 = relatedEntitiesQueryValue.EntityName == fakeRelationship.Entity1LogicalName || request.Target.LogicalName != fakeRelationship.Entity1LogicalName || string.IsNullOrWhiteSpace(relatedEntitiesQueryValue.EntityName); if (isFrom1to2) { var fromAttribute = isFrom1to2 ? fakeRelationship.Entity1Attribute : fakeRelationship.Entity2Attribute; var toAttribute = isFrom1to2 ? fakeRelationship.Entity2Attribute : fakeRelationship.Entity1Attribute; var linkEntity = new LinkEntity { Columns = new ColumnSet(false), LinkFromAttributeName = fromAttribute, LinkFromEntityName = retrieveRelatedEntitiesQuery.EntityName, LinkToAttributeName = toAttribute, LinkToEntityName = resultEntity.LogicalName }; if (retrieveRelatedEntitiesQuery.Criteria == null) { retrieveRelatedEntitiesQuery.Criteria = new FilterExpression(); } retrieveRelatedEntitiesQuery.Criteria .AddFilter(LogicalOperator.And) .AddCondition(linkEntity.LinkFromAttributeName, ConditionOperator.Equal, resultEntity.Id); } else { var link = retrieveRelatedEntitiesQuery.AddLink(fakeRelationship.Entity1LogicalName, fakeRelationship.Entity2Attribute, fakeRelationship.Entity1Attribute); link.LinkCriteria.AddCondition(resultEntity.LogicalName + "id", ConditionOperator.Equal, resultEntity.Id); } } else { var isFrom1 = fakeRelationship.Entity1LogicalName == retrieveRelatedEntitiesQuery.EntityName; var linkAttributeName = isFrom1 ? fakeRelationship.Entity1Attribute : fakeRelationship.Entity2Attribute; var conditionAttributeName = isFrom1 ? fakeRelationship.Entity2Attribute : fakeRelationship.Entity1Attribute; var linkEntity = new LinkEntity { Columns = new ColumnSet(false), LinkFromAttributeName = linkAttributeName, LinkFromEntityName = retrieveRelatedEntitiesQuery.EntityName, LinkToAttributeName = linkAttributeName, LinkToEntityName = fakeRelationship.IntersectEntity, LinkCriteria = new FilterExpression { Conditions = { new ConditionExpression(conditionAttributeName, ConditionOperator.Equal, resultEntity.Id) } } }; retrieveRelatedEntitiesQuery.LinkEntities.Add(linkEntity); } var retrieveRelatedEntitiesRequest = new RetrieveMultipleRequest { Query = retrieveRelatedEntitiesQuery }; //use of an executor directly; if to use service.RetrieveMultiple then the result will be //limited to the number of records per page (somewhere in future release). //ALL RECORDS are needed here. var executor = new RetrieveMultipleRequestExecutor(); var retrieveRelatedEntitiesResponse = executor .Execute(retrieveRelatedEntitiesRequest, context) as RetrieveMultipleResponse; if (retrieveRelatedEntitiesResponse.EntityCollection.Entities.Count == 0) { continue; } resultEntity.RelatedEntities .Add(relatedEntitiesQuery.Key, retrieveRelatedEntitiesResponse.EntityCollection); } } return(new RetrieveResponse { Results = new ParameterCollection { { "Entity", resultEntity } } }); } else { // Entity not found in the context => FaultException throw new FaultException <OrganizationServiceFault>(new OrganizationServiceFault(), $"{entityName} With Id = {id:D} Does Not Exist"); } }
public static Entity ProjectAttributes(this Entity e, QueryExpression qe, XrmFakedContext context) { if (qe.ColumnSet == null) return e; if (qe.ColumnSet.AllColumns) { return e; //return all the original attributes } else { //Return selected list of attributes in a projected entity Entity projected = null; //However, if we are using proxy types, we must create a instance of the appropiate class if (context.ProxyTypesAssembly != null) { var subClassType = context.FindReflectedType(e.LogicalName); if (subClassType != null) { var instance = Activator.CreateInstance(subClassType); projected = (Entity)instance; projected.Id = e.Id; } else projected = new Entity(e.LogicalName) { Id = e.Id }; //fallback to generic type if type not found } else projected = new Entity(e.LogicalName) { Id = e.Id }; foreach (var attKey in qe.ColumnSet.Columns) { //Check if attribute really exists in metadata if (!context.AttributeExistsInMetadata(e.LogicalName, attKey)) { OrganizationServiceFaultQueryBuilderNoAttributeException.Throw(attKey); } if (e.Attributes.ContainsKey(attKey)) projected[attKey] = e[attKey]; else { projected[attKey] = null; } } //Plus attributes from joins foreach(var le in qe.LinkEntities) { ProjectAttributes(e, projected, le, context); } //foreach (var attKey in e.Attributes.Keys) //{ // if(e[attKey] is AliasedValue && !projected.Attributes.ContainsKey(attKey)) // projected[attKey] = e[attKey]; //} return projected; } }
public static object GetConditionExpressionValueCast(string value, XrmFakedContext ctx, string sEntityName, string sAttributeName) { if (ctx.ProxyTypesAssembly != null) { //We have proxy types so get appropiate type value based on entity name and attribute type var reflectedType = ctx.FindReflectedType(sEntityName); if (reflectedType != null) { var attributeType = ctx.FindReflectedAttributeType(reflectedType, sAttributeName); if (attributeType != null) { try { return GetValueBasedOnType(attributeType, value); } catch (Exception e) { throw new Exception(string.Format("When trying to parse value for entity {0} and attribute {1}: {2}", sEntityName, sAttributeName, e.Message)); } } } } //Try parsing a guid Guid gOut = Guid.Empty; if (Guid.TryParse(value, out gOut)) return gOut; //Try checking if it is a numeric value, cause, from the fetchxml it //would be impossible to know the real typed based on the string value only // ex: "123" might compared as a string, or, as an int, it will depend on the attribute // data type, therefore, in this case we do need to use proxy types bool bIsNumeric = false; bool bIsDateTime = false; double dblValue = 0.0; decimal decValue = 0.0m; int intValue = 0; if (double.TryParse(value, out dblValue)) bIsNumeric = true; if (decimal.TryParse(value, out decValue)) bIsNumeric = true; if (int.TryParse(value, out intValue)) bIsNumeric = true; DateTime dtValue = DateTime.MinValue; if (DateTime.TryParse(value, out dtValue)) bIsDateTime = true; if(bIsNumeric || bIsDateTime) { throw new Exception("When using arithmetic values in Fetch a ProxyTypesAssembly must be used in order to know which types to cast values to."); } //Default value return value; }