public Expression BuildSelect(SelectExpandClause selectClause, Expression source, bool navigationNextLink, bool skipToken) { foreach (SelectItem selectItemClause in selectClause.SelectedItems) { var selectItemTranslator = new OeSelectItemTranslator(_navigationItem, navigationNextLink, source, _joinBuilder, skipToken); OeSelectItem selectItem = selectItemClause.TranslateWith(selectItemTranslator); if (selectItem != null) { if (selectItem.EdmProperty is IEdmNavigationProperty) { source = selectItemTranslator.Source; } else { _navigationItem.AddSelectItem(selectItem); } } } if (_navigationItem.SelectItems.Count > 0) { AddKey(_metadataLevel != OeMetadataLevel.Full); } return(source); }
internal OeSelectTranslator(OeJoinBuilder joinBuilder, OeSelectItem navigationItem) { _joinBuilder = joinBuilder; _navigationItem = navigationItem; _visitor = joinBuilder.Visitor; _metadataLevel = OeMetadataLevel.None; }
private static OeEntryFactory CreateEntryFactory(IEdmModel edmModel, OeSelectItem root, Type clrType) { ParameterExpression parameter = Expression.Parameter(typeof(Object)); UnaryExpression typedParameter = Expression.Convert(parameter, clrType); if (root.HasNavigationItems) { List <OeSelectItem> navigationItems = FlattenNavigationItems(root, false); IReadOnlyList <MemberExpression> navigationProperties = OeExpressionHelper.GetPropertyExpressions(typedParameter); for (int i = navigationItems.Count - 1; i >= 0; i--) { OeSelectItem navigationItem = navigationItems[i]; OeEntryFactory[] nestedNavigationLinks = GetNestedNavigationLinks(navigationItem); OeEntryFactory entryFactory; Type clrEntityType = edmModel.GetClrType(navigationItem.EntitySet); OePropertyAccessor[] accessors = GetAccessors(navigationProperties[i].Type, navigationItem.EntitySet, navigationItem.SelectItems); LambdaExpression linkAccessor = Expression.Lambda(navigationProperties[i], parameter); if (i == 0) { entryFactory = OeEntryFactory.CreateEntryFactoryParent(clrEntityType, navigationItem.EntitySet, accessors, nestedNavigationLinks, linkAccessor); } else { var resourceInfo = new ODataNestedResourceInfo() { IsCollection = navigationItem.EdmProperty.Type.Definition is EdmCollectionType, Name = navigationItem.EdmProperty.Name }; entryFactory = OeEntryFactory.CreateEntryFactoryNested(clrEntityType, navigationItem.EntitySet, accessors, nestedNavigationLinks, linkAccessor, resourceInfo); entryFactory.CountOption = navigationItem.ExpandedNavigationSelectItem.CountOption; } navigationItem.EntryFactory = entryFactory; } } else { IReadOnlyList <MemberExpression> propertyExpressions = OeExpressionHelper.GetPropertyExpressions(typedParameter); OePropertyAccessor[] accessors; if (root.SelectItems.Count == 0) { accessors = OePropertyAccessor.CreateFromType(typedParameter.Type, root.EntitySet); } else { var accessorList = new List <OePropertyAccessor>(root.SelectItems.Count); for (int i = 0; i < root.SelectItems.Count; i++) { OeSelectItem selectItem = root.SelectItems[i]; accessorList.Add(OePropertyAccessor.CreatePropertyAccessor(selectItem.EdmProperty, propertyExpressions[i], parameter, selectItem.SkipToken)); } accessors = accessorList.ToArray(); } Type clrEntityType = edmModel.GetClrType(root.EntitySet); root.EntryFactory = OeEntryFactory.CreateEntryFactory(clrEntityType, root.EntitySet, accessors); } return(root.EntryFactory); }
private static Expression BuildOrderBySkipToken(OeSelectItem navigationItem, OrderByClause orderByClause, Expression source, OeJoinBuilder joinBuilder, bool hasSelectItems) { while (orderByClause != null) { var propertyNode = (SingleValuePropertyAccessNode)orderByClause.Expression; if (propertyNode.Source is SingleNavigationNode navigationNode) { OeSelectItem match = null; ExpandedNavigationSelectItem navigationSelectItem = null; do { if ((match = navigationItem.FindHierarchyNavigationItem(navigationNode.NavigationProperty)) != null) { match.AddSelectItem(new OeSelectItem(propertyNode.Property, true)); break; } SelectExpandClause selectExpandClause; if (navigationSelectItem == null) { var pathSelectItem = new PathSelectItem(new ODataSelectPath(new PropertySegment((IEdmStructuralProperty)propertyNode.Property))); selectExpandClause = new SelectExpandClause(new[] { pathSelectItem }, false); } else { selectExpandClause = new SelectExpandClause(new[] { navigationSelectItem }, false); } var segment = new NavigationPropertySegment(navigationNode.NavigationProperty, navigationNode.NavigationSource); navigationSelectItem = new ExpandedNavigationSelectItem(new ODataExpandPath(segment), navigationNode.NavigationSource, selectExpandClause); }while ((navigationNode = navigationNode.Source as SingleNavigationNode) != null); if (navigationSelectItem != null) { if (match == null) { match = navigationItem; } var selectItemTranslator = new OeSelectItemTranslator(match, false, source, joinBuilder, true); navigationSelectItem.TranslateWith(selectItemTranslator); source = selectItemTranslator.Source; } } else { if (hasSelectItems) { navigationItem.AddSelectItem(new OeSelectItem(propertyNode.Property, true)); } } orderByClause = orderByClause.ThenBy; } return(source); }
public IReadOnlyList <IEdmNavigationProperty> GetJoinPath() { var joinPath = new List <IEdmNavigationProperty>(); for (OeSelectItem navigationItem = this; navigationItem.Parent != null; navigationItem = navigationItem.Parent) { joinPath.Insert(0, (IEdmNavigationProperty)navigationItem.EdmProperty); } return(joinPath); }
private static OeEntryFactory[] GetNestedNavigationLinks(OeSelectItem navigationItem) { var nestedEntryFactories = new List <OeEntryFactory>(navigationItem.NavigationItems.Count); for (int i = 0; i < navigationItem.NavigationItems.Count; i++) { if (!navigationItem.NavigationItems[i].SkipToken) { nestedEntryFactories.Add(navigationItem.NavigationItems[i].EntryFactory); } } return(nestedEntryFactories.ToArray()); }
public OeSelectItem(IEdmModel edmModel, OeSelectItem parent, ExpandedNavigationSelectItem expandedNavigationSelectItem, bool skipToken) : this() { var segment = (NavigationPropertySegment)expandedNavigationSelectItem.PathToNavigationProperty.LastSegment; var segments = new List <ODataPathSegment>(parent.Path); segments.AddRange(expandedNavigationSelectItem.PathToNavigationProperty); EdmProperty = segment.NavigationProperty; EntitySet = (IEdmEntitySetBase)expandedNavigationSelectItem.NavigationSource ?? OeEdmClrHelper.GetEntitySet(edmModel, segment.NavigationProperty); ExpandedNavigationSelectItem = expandedNavigationSelectItem; Parent = parent; Path = new ODataPath(segments); SkipToken = skipToken; }
public bool AddSelectItem(OeSelectItem selectItem) { int existsSelectItemIndex; if ((existsSelectItemIndex = FindSelectItem(selectItem.EdmProperty)) != -1) { if (_selectItems[existsSelectItemIndex].SkipToken && !selectItem.SkipToken) { _selectItems[existsSelectItemIndex] = selectItem; } return(false); } _selectItems.Add(selectItem); return(true); }
public OeSelectItem FindHierarchyNavigationItem(IEdmNavigationProperty navigationProperty) { if (EdmProperty == navigationProperty) { return(this); } for (int i = 0; i < _navigationItems.Count; i++) { OeSelectItem matched = _navigationItems[i].FindHierarchyNavigationItem(navigationProperty); if (matched != null) { return(matched); } } return(null); }
private static List <OeSelectItem> FlattenNavigationItems(OeSelectItem root, bool skipToken) { var navigationItems = new List <OeSelectItem>(); var stack = new Stack <ValueTuple <OeSelectItem, int> >(); stack.Push(new ValueTuple <OeSelectItem, int>(root, 0)); do { ValueTuple <OeSelectItem, int> stackItem = stack.Pop(); if (stackItem.Item2 == 0 && (!stackItem.Item1.SkipToken || skipToken)) { navigationItems.Add(stackItem.Item1); } if (stackItem.Item2 < stackItem.Item1.NavigationItems.Count) { stack.Push(new ValueTuple <OeSelectItem, int>(stackItem.Item1, stackItem.Item2 + 1)); OeSelectItem selectItem = stackItem.Item1.NavigationItems[stackItem.Item2]; stack.Push(new ValueTuple <OeSelectItem, int>(selectItem, 0)); } }while (stack.Count > 0); return(navigationItems); }
public void AddNavigationItem(OeSelectItem navigationItem) { _navigationItems.Add(navigationItem); }
internal OeSelectTranslator(OeJoinBuilder joinBuilder, OeSelectItem navigationItem) { _joinBuilder = joinBuilder; _navigationItem = navigationItem; _visitor = joinBuilder.Visitor; }
private static Expression SelectStructuralProperties(Expression source, OeSelectItem 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 <OeSelectItem> navigationItems = FlattenNavigationItems(root, true); for (int i = 0; i < navigationItems.Count; i++) { newJoins[i] = joins[i]; if (navigationItems[i].SelectItems.Count > 0) { var properties = new Expression[navigationItems[i].SelectItems.Count]; for (int j = 0; j < navigationItems[i].SelectItems.Count; j++) { if (navigationItems[i].SelectItems[j].EdmProperty is ComputeProperty computeProperty) { properties[j] = new ReplaceParameterVisitor(joins[i]).Visit(computeProperty.Expression); } else { PropertyInfo property = OeEdmClrHelper.GetPropertyIgnoreCase(joins[i].Type, navigationItems[i].SelectItems[j].EdmProperty); properties[j] = Expression.Property(joins[i], property); } } Expression newTupleExpression = OeExpressionHelper.CreateTupleExpression(properties); if (i > 0 && navigationItems[i].EdmProperty.Type.IsNullable) { 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 Expression BuildSkipTakeSource(Expression source, OeQueryContext queryContext, OeSelectItem navigationItem) { bool hasSelectItems = HasSelectItems(queryContext.ODataUri.SelectAndExpand); source = BuildOrderBySkipToken(navigationItem, queryContext.ODataUri.OrderBy, source, queryContext.JoinBuilder, hasSelectItems); queryContext.JoinBuilder.Visitor.ChangeParameterType(source); var expressionBuilder = new OeExpressionBuilder(queryContext.JoinBuilder); source = expressionBuilder.ApplySkipToken(source, queryContext.SkipTokenNameValues, queryContext.ODataUri.OrderBy, queryContext.IsDatabaseNullHighestValue); source = expressionBuilder.ApplyOrderBy(source, queryContext.ODataUri.OrderBy); source = expressionBuilder.ApplySkip(source, queryContext.ODataUri.Skip, queryContext.ODataUri.Path); return(expressionBuilder.ApplyTake(source, queryContext.ODataUri.Top, queryContext.ODataUri.Path)); }