public static IQueryable <Entity> TranslateQueryExpressionToLinq(XrmFakedContext context, QueryExpression qe) { if (qe == null) { return(null); } //Start form the root entity and build a LINQ query to execute the query against the In-Memory context: context.EnsureEntityNameExistsInMetadata(qe.EntityName); IQueryable <Entity> query = null; query = context.CreateQuery <Entity>(qe.EntityName); //Add as many Joins as linked entities foreach (LinkEntity le in qe.LinkEntities) { query = TranslateLinkedEntityToLinq(context, le, query, qe.ColumnSet); } // Compose the expression tree that represents the parameter to the predicate. ParameterExpression entity = Expression.Parameter(typeof(Entity)); var expTreeBody = TranslateQueryExpressionFiltersToExpression(qe, entity); Expression <Func <Entity, bool> > lambda = Expression.Lambda <Func <Entity, bool> >(expTreeBody, entity); query = query.Where(lambda); //Project the attributes in the root column set (must be applied after the where clause, not before!!) query = query.Select(x => x.ProjectAttributes(qe, context)); //Sort results if (qe.Orders != null) { foreach (var order in qe.Orders) { if (order.OrderType == OrderType.Ascending) { query = query.OrderBy(e => e.Attributes.ContainsKey(order.AttributeName) ? e.Attributes[order.AttributeName] : null, new XrmOrderByAttributeComparer()); } else { query = query.OrderByDescending(e => e.Attributes.ContainsKey(order.AttributeName) ? e.Attributes[order.AttributeName] : null, new XrmOrderByAttributeComparer()); } } } //Apply TopCount if (qe.TopCount != null) { query = query.Take(qe.TopCount.Value); } return(query); }
public static IQueryable <Entity> TranslateLinkedEntityToLinq(XrmFakedContext context, LinkEntity le, IQueryable <Entity> query, ColumnSet previousColumnSet, string linkFromAlias = "") { var leAlias = string.IsNullOrWhiteSpace(le.EntityAlias) ? le.LinkToEntityName : le.EntityAlias; context.EnsureEntityNameExistsInMetadata(le.LinkFromEntityName); context.EnsureEntityNameExistsInMetadata(le.LinkToEntityName); if (!context.AttributeExistsInMetadata(le.LinkToEntityName, le.LinkToAttributeName)) { OrganizationServiceFaultQueryBuilderNoAttributeException.Throw(le.LinkToAttributeName); } var inner = context.CreateQuery <Entity>(le.LinkToEntityName); //if (!le.Columns.AllColumns && le.Columns.Columns.Count == 0) //{ // le.Columns.AllColumns = true; //Add all columns in the joined entity, otherwise we can't filter by related attributes, then the Select will actually choose which ones we need //} if (string.IsNullOrWhiteSpace(linkFromAlias)) { linkFromAlias = le.LinkFromAttributeName; } else { linkFromAlias += "." + le.LinkFromAttributeName; } switch (le.JoinOperator) { case JoinOperator.Inner: case JoinOperator.Natural: query = query.Join(inner, outerKey => outerKey.KeySelector(linkFromAlias, context), innerKey => innerKey.KeySelector(le.LinkToAttributeName, context), (outerEl, innerEl) => outerEl .JoinAttributes(innerEl, new ColumnSet(true), leAlias, context)); break; case JoinOperator.LeftOuter: query = query.GroupJoin(inner, outerKey => outerKey.KeySelector(le.LinkFromAttributeName, context), innerKey => innerKey.KeySelector(le.LinkToAttributeName, context), (outerEl, innerElemsCol) => new { outerEl, innerElemsCol }) .SelectMany(x => x.innerElemsCol.DefaultIfEmpty() , (x, y) => x.outerEl .JoinAttributes(y, new ColumnSet(true), leAlias, context)); break; default: //This shouldn't be reached as there are only 3 types of Join... throw new PullRequestException(string.Format("The join operator {0} is currently not supported. Feel free to implement and send a PR.", le.JoinOperator)); } //Process nested linked entities recursively foreach (LinkEntity nestedLinkedEntity in le.LinkEntities) { if (string.IsNullOrWhiteSpace(le.EntityAlias)) { le.EntityAlias = le.LinkToEntityName; } query = TranslateLinkedEntityToLinq(context, nestedLinkedEntity, query, le.Columns, le.EntityAlias); } return(query); }