private MethodCallExpression CreateSelectExpression(Expression source) { if (_rootNavigationItem.HasNavigationItems()) { return((MethodCallExpression)source); } if (_rootNavigationItem.AllSelected) { return((MethodCallExpression)source); } ParameterExpression parameter = _joinBuilder.Visitor.Parameter; IReadOnlyList <OeStructuralSelectItem> structuralItems = _rootNavigationItem.GetStructuralItemsWithNotSelected(); var expressions = new Expression[structuralItems.Count]; for (int i = 0; i < expressions.Length; i++) { if (structuralItems[i].EdmProperty is ComputeProperty computeProperty) { expressions[i] = computeProperty.Expression; } else { PropertyInfo clrProperty = parameter.Type.GetPropertyIgnoreCase(structuralItems[i].EdmProperty); expressions[i] = Expression.MakeMemberAccess(parameter, clrProperty); } } NewExpression newTupleExpression = OeExpressionHelper.CreateTupleExpression(expressions); LambdaExpression lambda = Expression.Lambda(newTupleExpression, parameter); MethodInfo selectMethodInfo = OeMethodInfoHelper.GetSelectMethodInfo(parameter.Type, newTupleExpression.Type); return(Expression.Call(selectMethodInfo, source, lambda)); }
public override OeEntryFactory CreateEntryFactory(IEdmEntitySet entitySet, Type clrType, OePropertyAccessor[]?skipTokenAccessors) { ParameterExpression parameter = Expression.Parameter(typeof(Object)); UnaryExpression typedParameter = Expression.Convert(parameter, clrType); if (_rootNavigationItem.HasNavigationItems()) { List <OeNavigationSelectItem> navigationItems = OeSelectTranslator.FlattenNavigationItems(_rootNavigationItem, true); IReadOnlyList <MemberExpression> navigationProperties = OeExpressionHelper.GetPropertyExpressions(typedParameter); int propertyIndex = navigationProperties.Count - 1; for (int i = navigationItems.Count - 1; i >= 0; i--) { OeNavigationSelectItem navigationItem = navigationItems[i]; if (navigationItem.Kind == OeNavigationSelectItemKind.NotSelected) { propertyIndex--; continue; } OePropertyAccessor[] accessors = Array.Empty <OePropertyAccessor>(); LambdaExpression? linkAccessor = null; OeNavigationEntryFactory[] nestedNavigationLinks = Array.Empty <OeNavigationEntryFactory>(); if (navigationItem.Kind != OeNavigationSelectItemKind.NextLink) { accessors = GetAccessors(navigationProperties[propertyIndex].Type, navigationItem); linkAccessor = Expression.Lambda(navigationProperties[propertyIndex], parameter); nestedNavigationLinks = GetNestedNavigationLinks(navigationItem); propertyIndex--; } if (i == 0) { navigationItem.EntryFactory = new OeEntryFactory(navigationItem.EntitySet, accessors, skipTokenAccessors, nestedNavigationLinks, linkAccessor); } else { navigationItem.EntryFactory = new OeNavigationEntryFactory( navigationItem.EntitySet, accessors, skipTokenAccessors, nestedNavigationLinks, linkAccessor, navigationItem.EdmProperty, navigationItem.NavigationSelectItem, navigationItem.Kind == OeNavigationSelectItemKind.NextLink); } } } else { var navigationLinks = new OeNavigationEntryFactory[_rootNavigationItem.NavigationItems.Count]; for (int i = 0; i < _rootNavigationItem.NavigationItems.Count; i++) { OeNavigationSelectItem navigationItem = _rootNavigationItem.NavigationItems[i]; navigationLinks[i] = new OeNavigationEntryFactory( navigationItem.EntitySet, Array.Empty <OePropertyAccessor>(), null, Array.Empty <OeNavigationEntryFactory>(), null, navigationItem.EdmProperty, navigationItem.NavigationSelectItem, navigationItem.Kind == OeNavigationSelectItemKind.NextLink); } OePropertyAccessor[] accessors = GetAccessors(clrType, _rootNavigationItem); _rootNavigationItem.EntryFactory = new OeEntryFactory(_rootNavigationItem.EntitySet, accessors, skipTokenAccessors, navigationLinks); } return(_rootNavigationItem.EntryFactory); }
private static Expression SelectStructuralProperties(Expression source, OeNavigationSelectItem root) { if (!root.HasNavigationItems()) { return(source); } ParameterExpression parameter = Expression.Parameter(OeExpressionHelper.GetCollectionItemType(source.Type)); IReadOnlyList <MemberExpression> joins = OeExpressionHelper.GetPropertyExpressions(parameter); var newJoins = new Expression[joins.Count]; List <OeNavigationSelectItem> navigationItems = FlattenNavigationItems(root, false); bool isNavigationNullable = false; for (int i = 0; i < navigationItems.Count; i++) { newJoins[i] = joins[i]; isNavigationNullable |= i > 0 && navigationItems[i].EdmProperty.Type.IsNullable; if (!navigationItems[i].AllSelected) { IReadOnlyList <OeStructuralSelectItem> structuralItems = navigationItems[i].GetStructuralItemsWithNotSelected(); if (structuralItems.Count > 0) { var properties = new Expression[structuralItems.Count]; for (int j = 0; j < structuralItems.Count; j++) { if (structuralItems[j].EdmProperty is ComputeProperty computeProperty) { properties[j] = new ReplaceParameterVisitor(joins[i]).Visit(computeProperty.Expression); } else { PropertyInfo property = joins[i].Type.GetPropertyIgnoreCase(structuralItems[j].EdmProperty); properties[j] = Expression.Property(joins[i], property); } } Expression newTupleExpression = OeExpressionHelper.CreateTupleExpression(properties); if (isNavigationNullable) { UnaryExpression nullConstant = Expression.Convert(OeConstantToVariableVisitor.NullConstantExpression, newTupleExpression.Type); newTupleExpression = Expression.Condition(Expression.Equal(joins[i], OeConstantToVariableVisitor.NullConstantExpression), nullConstant, newTupleExpression); } newJoins[i] = newTupleExpression; } } } NewExpression newSelectorBody = OeExpressionHelper.CreateTupleExpression(newJoins); MethodInfo selectMethodInfo = OeMethodInfoHelper.GetSelectMethodInfo(parameter.Type, newSelectorBody.Type); LambdaExpression newSelector = Expression.Lambda(newSelectorBody, parameter); //Quirk EF Core 2.1.1 bug Take/Skip must be last in expression tree var skipTakeExpressions = new List <MethodCallExpression>(); while (source is MethodCallExpression callExpression && (callExpression.Method.Name == nameof(Enumerable.Skip) || callExpression.Method.Name == nameof(Enumerable.Take))) { skipTakeExpressions.Add(callExpression); source = callExpression.Arguments[0]; } source = Expression.Call(selectMethodInfo, source, newSelector); for (int i = skipTakeExpressions.Count - 1; i >= 0; i--) { MethodInfo skipTakeMethodInfo = skipTakeExpressions[i].Method.GetGenericMethodDefinition().MakeGenericMethod(newSelector.ReturnType); source = Expression.Call(skipTakeMethodInfo, source, skipTakeExpressions[i].Arguments[1]); } return(source); }
private static OeEntryFactory CreateEntryFactory(OeNavigationSelectItem root, Type clrType, OePropertyAccessor[] skipTokenAccessors) { ParameterExpression parameter = Expression.Parameter(typeof(Object)); UnaryExpression typedParameter = Expression.Convert(parameter, clrType); if (!root.HasNavigationItems()) { var navigationLinks = new OeEntryFactory[root.NavigationItems.Count]; for (int i = 0; i < root.NavigationItems.Count; i++) { OeNavigationSelectItem navigationItem = root.NavigationItems[i]; var nextLinkOptions = new OeEntryFactoryOptions() { Accessors = Array.Empty <OePropertyAccessor>(), EdmNavigationProperty = navigationItem.EdmProperty, EntitySet = navigationItem.EntitySet, NavigationSelectItem = navigationItem.NavigationSelectItem, NextLink = navigationItem.Kind == OeNavigationSelectItemKind.NextLink }; navigationLinks[i] = new OeEntryFactory(ref nextLinkOptions); } var options = new OeEntryFactoryOptions() { Accessors = GetAccessors(clrType, root), EntitySet = root.EntitySet, NavigationLinks = navigationLinks, SkipTokenAccessors = skipTokenAccessors }; root.EntryFactory = new OeEntryFactory(ref options); } else { List <OeNavigationSelectItem> navigationItems = FlattenNavigationItems(root, true); IReadOnlyList <MemberExpression> navigationProperties = OeExpressionHelper.GetPropertyExpressions(typedParameter); int propertyIndex = navigationProperties.Count - 1; for (int i = navigationItems.Count - 1; i >= 0; i--) { OeNavigationSelectItem navigationItem = navigationItems[i]; if (navigationItem.Kind == OeNavigationSelectItemKind.NotSelected) { propertyIndex--; continue; } OePropertyAccessor[] accessors = Array.Empty <OePropertyAccessor>(); LambdaExpression? linkAccessor = null; OeEntryFactory[] nestedNavigationLinks = Array.Empty <OeEntryFactory>(); if (navigationItem.Kind != OeNavigationSelectItemKind.NextLink) { accessors = GetAccessors(navigationProperties[propertyIndex].Type, navigationItem); linkAccessor = Expression.Lambda(navigationProperties[propertyIndex], parameter); nestedNavigationLinks = GetNestedNavigationLinks(navigationItem); propertyIndex--; } var options = new OeEntryFactoryOptions() { Accessors = accessors, EdmNavigationProperty = navigationItem.Parent == null ? null : navigationItem.EdmProperty, EntitySet = navigationItem.EntitySet, LinkAccessor = linkAccessor, NavigationLinks = nestedNavigationLinks, NavigationSelectItem = navigationItem.Parent == null ? null : navigationItem.NavigationSelectItem, NextLink = navigationItem.Kind == OeNavigationSelectItemKind.NextLink, SkipTokenAccessors = skipTokenAccessors }; navigationItem.EntryFactory = new OeEntryFactory(ref options); } } return(root.EntryFactory); }